zoukankan      html  css  js  c++  java
  • 【codevs2370】小机房的树——倍增法/链剖求LCA

    题目链接

    这道题就是LCA的完全模版题了,之前学倍增的时候写过一次,但是太久没复习忘了......

    滚回来重新学了一波,赶紧写篇博客记录一下~

    倍增法求LCA的基本思路:先dfs预处理出每个节点i的祖先2^j表示为gr[i][j]、深度deep[i]以及到祖先2^j 的距离dis[i][j]。然后对于每个询问x和y的最近公共祖先,先钦定(?)y在x的下方,然后先让y跳到x这一层,而(1<<i)&d巧妙地运用位运算让y能恰好用最少步数跳到x这一层。如果此时x==y即说明x是y的祖先,可以直接返回答案;否则就从大到小枚举倍增,这个地方也是倍增法的核心,要好好理解其中的巧妙之处。

    要注意的地方:

    1,根节点为0;

    2.gr[i][0]即为节点i的父节点;

    3.当y跳到x这一层时要注意判断x是否为y的祖先;

    4.倍增结束时要记得x和y还要跳到他们的父节点上,ans不要忘记加上dis[x][0]和dis[y][0]。

    其他细节详见代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    const int M=5e4+10;
    using namespace std;
    struct point{
        int to,next,w;
    }e[M*2];
    int n,m,sum=0,u,v,wi,first[M],deep[M];
    bool ok[M];
    int gr[M][22],dis[M][22];
    int read()
    {
        int ans=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();}
        return ans*f;
    }
    void add(int x,int y,int z)
    {
        sum++;e[sum].to=y;e[sum].w=z;e[sum].next=first[x];first[x]=sum;
        sum++;e[sum].to=x;e[sum].w=z;e[sum].next=first[y];first[y]=sum;
    }
    void dfs(int x)
    {
        ok[x]=1;
        for(int i=1;i<=20;i++){
            if((1<<i)>deep[x])break;
            gr[x][i]=gr[gr[x][i-1]][i-1];
            dis[x][i]=dis[x][i-1]+dis[gr[x][i-1]][i-1];
        }
        for(int i=first[x];i>0;i=e[i].next){
            int now=e[i].to;
            if(ok[now])continue;
            deep[now]=deep[x]+1;
            gr[now][0]=x;
            dis[now][0]=e[i].w;
            dfs(now);
        }
    }
    inline int lca(int x,int y)
    {
        int ans=0;
        if(deep[x]>deep[y])swap(x,y);
        int d=deep[y]-deep[x];
        for(int i=0;i<=20;i++)
            if((1<<i)&d){
                ans+=dis[y][i];
                y=gr[y][i];
            }
        if(x==y)return ans;
        for(int i=20;i>=0;i--){
            if(gr[x][i]!=gr[y][i]){
                ans+=dis[x][i]+dis[y][i];
                x=gr[x][i];y=gr[y][i];
            }
        }
        ans+=dis[x][0]+dis[y][0];
        return ans;
    }
    int main()
    {
        memset(first,-1,sizeof(first));
        n=read();int a,b;
        for(int i=1;i<=n-1;i++){
            u=read();v=read();wi=read();
            add(u,v,wi);
        }
        dfs(0);
        m=read();
        while(m--){
            a=read();b=read();
            printf("%d
    ",lca(a,b));
        }
        return 0;
    }
    codevs2370

     2017/9/21:

    今天跟着ccz学了一波树链剖分求lca,理解完之后发现链剖无论是时间还是空间都完踩倍增诶>.<

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 const int N=5e4+10;
     5 int tot=0,first[N],n,m;
     6 int dis[N];
     7 struct node{
     8     int ne,to,w;
     9 }e[N*2];
    10 struct point{
    11     int son,fa,top,sz,dep;
    12 }q[N];
    13 void read(int &x){
    14     int f=1;x=0;char c=getchar();
    15     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    16     while(c>='0'&&c<='9'){x=x*10+c-48;c=getchar();}
    17     x*=f;
    18 }
    19 void ins(int u,int v,int w){
    20     e[++tot]=(node){first[u],v,w};first[u]=tot;
    21     e[++tot]=(node){first[v],u,w};first[v]=tot;
    22 }
    23 void dfs(int x,int fa){
    24     point&w=q[x];
    25     w.sz=1;
    26     for(int i=first[x];i;i=e[i].ne){
    27         int to=e[i].to;
    28         if(to!=fa){
    29             point&u=q[to];dis[to]=dis[x]+e[i].w;
    30             u.dep=w.dep+1;u.fa=x;
    31             dfs(to,x);w.sz+=u.sz;if(q[w.son].sz<u.sz)w.son=to;
    32         }
    33     }
    34 }
    35 void dfs1(int x,int tp){
    36     point&w=q[x];w.top=tp;
    37     for(int i=first[x];i;i=e[i].ne){
    38         int to=e[i].to;
    39         if(to!=w.fa){
    40             if(to==w.son)dfs1(to,tp);
    41             else dfs1(to,to);
    42         }
    43     }
    44 }
    45 int lca(int x,int y){
    46     int a=q[x].top,b=q[y].top;
    47     while(a!=b){
    48         if(q[a].dep>q[b].dep)x=q[a].fa,a=q[x].top;
    49         else y=q[b].fa,b=q[y].top;
    50     }
    51     if(q[x].dep<q[y].dep)return x;
    52     return y;
    53 }
    54 int main(){
    55     read(n);
    56     for(int i=1,a,b,c;i<n;i++){
    57         read(a);read(b);read(c);a++;b++;ins(a,b,c);
    58     }
    59     dis[1]=0;dfs(1,0);dfs1(1,1);
    60     read(m);
    61     while(m--){
    62         int u,v;read(u);read(v);u++;v++;
    63         printf("%d
    ",dis[u]+dis[v]-2*dis[lca(u,v)]);
    64     }
    65     return 0;
    66 }
    链剖求lca
  • 相关阅读:
    Python for Data Science
    Python for Data Science
    Python for Data Science
    团队项目选题报告(I know)
    结对第一次作业——原型设计
    团队展示(I know)
    软件工程实践第二次作业——个人项目实战(数独)
    软件工程实践第一次作业--准备篇
    Java微笔记(9)
    Java微笔记(8)
  • 原文地址:https://www.cnblogs.com/JKAI/p/7301523.html
Copyright © 2011-2022 走看看