倍增lca学习小结

思路十分简单,就是设 f i , j 表示i向上跳 2 j j步,到达的结点,
状态转移方程就是 f i , j = f [ f [ i ] [ j 1 ] , j 1 ] 意思是先往上跳 2 j 1 ,接着再跳 2 j 1 .

code ##以洛谷3379为例

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
#define fd(i,a,b) for (int (i)=(a);(i)>=(b);(i)--)
using namespace std;
int f[500000+5][21],g[500000*3][21],next[500000*2+5],head[500000+5],to[500000*2+5],n,m,q;
int d[500000+5],tot;
void R(int &n)
{
    int t=0,p=1;char ch;
    for(ch=getchar();!('0'<=ch && ch<='9');ch=getchar())
        if(ch=='-') p=-1;
    for(;'0'<=ch && ch<='9';ch=getchar()) t=t*10+ch-'0';
    n=t*p;
}
void add(int x,int y)
{
    to[++tot]=y;
    next[tot]=head[x];
    head[x]=tot;
}
void dfs(int x,int y)
{
    for(int i=head[x];i;i=next[i])
    {
        int v=to[i];
        if (y!=v)
        {
            d[v]=d[x]+1;
            g[v][0]=x;
            dfs(v,x);
        }
    }
}
int  lca(int x,int y)
{
    if (d[x]<d[y])swap(x,y);
    fd(k,20,0)//为了将x,y跳到同样深度
        if (d[g[x][k]]>d[y]) x=g[x][k];
    if (d[x]!=d[y]) x=g[x][0];
    fd(k,20,0)
        if (g[x][k]!=g[y][k])//如果说两者等于,我们无法判断,到底是到了,还是跳过了(见下两行)。
            x=g[x][k],y=g[y][k];//you jump,I jump!
    if (x!=y) return g[x][0];//这就是为什么有可能不等的原因。
    else return x;
}
int main()
{
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);
    int x,y,s;
    R(n);R(m);R(s);
    fo(i,1,n-1)
    {
        R(x);R(y);
        add(x,y);add(y,x);
    }
    d[s]=1;
    dfs(s,0);
    fo(j,1,20)
        fo(i,1,n)
            g[i][j]=g[g[i][j-1]][j-1];
    while (m--)
    {
        R(x);R(y);
        printf("%d\n",lca(x,y));
    }
    return 0;
}

例题:SPOJ COT 树上第 K 大(未完待续)

猜你喜欢

转载自blog.csdn.net/ganjingxian/article/details/80559699