1. 程式人生 > 實用技巧 >HIT暑期集訓Day17 lca與rmq

HIT暑期集訓Day17 lca與rmq

rmq,求區間最大最小值模板,以POJ - 3264為例

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 50005
using namespace std;
int a[maxn],dp[maxn][30][2];
void ST(int n) 
{
    int i,j;
    for (i=1;i<=n;i++) dp[i][0][0]=dp[i][0][1]=a[i];
    for (j=1;(1<<j)<=n;j++) 
    {
        
for (i=1;i+(1<<j)-1<=n;i++) { dp[i][j][0]=max(dp[i][j-1][0],dp[i+(1<<(j-1))][j-1][0]); dp[i][j][1]=min(dp[i][j-1][1],dp[i+(1<<(j-1))][j-1][1]); } } } int getk(int l,int r) { int k=0; while ((1<<(k+1))<=r-l+1) k++; return
k; } int rmq_max(int l,int r,int k) { return max(dp[l][k][0],dp[r-(1<<k)+1][k][0]); } int rmq_min(int l,int r,int k) { return min(dp[l][k][1],dp[r-(1<<k)+1][k][1]); } int main() { int i,x,y,k,n,q,ans; scanf("%d%d",&n,&q); for (i=1;i<=n;i++) scanf("%d",&a[i]); ST(n);
while (q--) { scanf("%d%d",&x,&y); k=getk(x,y); ans=rmq_max(x,y,k)-rmq_min(x,y,k); printf("%d\n",ans); } return 0; }
rmq模板

樹鏈剖分求lca模板,以POJ - 1330為例

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 10005
using namespace std;
struct edge
{
    int to,nxt;
}e[maxn];
int num,last[maxn],deg[maxn];
int fa[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn];
void add(int x,int y)
{
    e[++num].to=y;
    e[num].nxt=last[x];
    last[x]=num;
}
void dfs1(int u,int father,int depth)  
{
    int i,v;
    fa[u]=father;
    dep[u]=depth;
    siz[u]=1;
    for (i=last[u];i;i=e[i].nxt)
    {
        v=e[i].to;
        if (v==father) continue;
        dfs1(v,u,depth+1);    
        siz[u]+=siz[v];    
        if (siz[v]>siz[son[u]]) son[u]=v;   
    }
}
void dfs2(int u,int tp)   
{
    top[u]=tp; 
    if (!son[u]) return;
    dfs2(son[u],tp);
    int i,v;
    for (i=last[u];i;i=e[i].nxt)
    {
        v=e[i].to;
        if (v!=son[u] && v!=fa[u]) dfs2(v,v);  
    }
}
int query(int x,int y)
{
    int tx=top[x],ty=top[y];
    while (tx!=ty)    
    {
        if (dep[tx]>=dep[ty]) x=fa[tx],tx=top[x];
        else y=fa[ty],ty=top[y];
    }
    if (dep[x]>dep[y]) return y;
    return x;
}
int main()
{
    int T,i,x,y,n,rt;
    scanf("%d",&T);
    while (T--)
    {
        num=0;
        memset(last,0,sizeof(last));
        memset(son,0,sizeof(son));
        memset(deg,0,sizeof(deg));
        scanf("%d",&n);
        for (i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);deg[y]++;
        }
        for (i=1;i<=n;i++)
            if (deg[i]==0) 
            {
                rt=i;break;
            }
        dfs1(rt,0,0);
        dfs2(rt,0);
        scanf("%d%d",&x,&y);
        printf("%d\n",query(x,y));
    }
    return 0;
}
樹鏈剖分求lca

D HYSBZ 1047

E CodeForces 803G

F CodeForces 832D

題意:給一棵樹,每次詢問給三個點,這三個點可以隨意排列,分別為s,f,t,問s到f的路徑上與t到f的路徑上有幾個兩路徑共有的節點。

可以發現答案為(dis[s->f]+dis[t->f]-dis[s->t])/2+1(由於是求共有節點所以要+1),而dis[x->y]=dep[x]+dep[y]-2*dep[lca(x,y)],用樹鏈剖分就可求出dep與lca,從而求出dis。

對於每次詢問,列舉三種f的情況,其中的最大值就是答案。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 100005
using namespace std;
struct edge
{
    int to,nxt;
}e[maxn<<1];
int num,last[maxn];
int fa[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn];
void add(int x,int y)
{
    e[++num].to=y;
    e[num].nxt=last[x];
    last[x]=num;
}
void dfs1(int u,int father,int depth)  
{
    int i,v;
    fa[u]=father;
    dep[u]=depth;
    siz[u]=1;
    for (i=last[u];i;i=e[i].nxt)
    {
        v=e[i].to;
        if (v==father) continue;
        dfs1(v,u,depth+1);    
        siz[u]+=siz[v];    
        if (siz[v]>siz[son[u]]) son[u]=v;   
    }
}
void dfs2(int u,int tp)   
{
    top[u]=tp;
    if (!son[u]) return;
    dfs2(son[u],tp);
    int i,v;
    for (i=last[u];i;i=e[i].nxt)
    {
        v=e[i].to;
        if (v!=son[u] && v!=fa[u]) dfs2(v,v);  
    }
}
int lca(int x,int y)
{
    int tx=top[x],ty=top[y];
    while (tx!=ty)    
    {
        if (dep[tx]>=dep[ty]) x=fa[tx],tx=top[x];
        else y=fa[ty],ty=top[y];
    }
    if (dep[x]>dep[y]) return y;
    return x;
}
int getdis(int x,int y)
{
    int xy=lca(x,y);
    return dep[x]+dep[y]-2*dep[xy];
} 
int getans(int s,int f,int t)
{
    return (getdis(s,f)+getdis(f,t)-getdis(s,t))/2;
} 
int main()
{
    int T,i,x,y,z,n,q,ans;
    while (scanf("%d%d",&n,&q)!=EOF)
    {
        num=0;
        memset(last,0,sizeof(last));
        memset(son,0,sizeof(son));
        for (i=2;i<=n;i++)
        {
            scanf("%d",&x);
            add(x,i);add(i,x);
        }
        dfs1(1,0,0);
        dfs2(1,0);
        while (q--)
        {
            scanf("%d%d%d",&x,&y,&z);
            ans=getans(x,y,z);
            ans=max(ans,getans(y,x,z));
            ans=max(ans,getans(x,z,y));
            printf("%d\n",ans+1);
        }
    }
    return 0;
}
View Code

G HDU 5023

H HYSBZ 4810

J POJ 2019