• 倍增 Tarjan 求LCA


                                                                                                                                                             ----代码都是  HDU 2586  "How far away" 为例

        倍增求LCA

     

      树上倍增法。

      设F[x,k] 表示x的2的k次方辈祖先,即 由x向上走2的k次方到达的节点

      F[x,k]=F[F[x][k-1],k-1]

       预处理: 这类似于一个动态规划的过程,阶段就是节点的深度,因此,我们可以对树进行bfs,按照层次顺序,下节点入队之前,计算它在F数组中相应的值。

      基于F数组计算LCA:

      1.设d[x]表示x的深度。不妨设d[x]>d[y]

      2.用二进制拆分思想,把x上调到与y同一深度

      3.若x=y则LCA=y

         否则 把x,y同时向上调整,并保持深度一致且二者不相会。

        具体来说,就是依次尝试把x,y同时向上走2的整数次方步(递减),在每此尝试中,若F[x,k]!=F[y,k],则令x=F[x,k],y=F[y,k]

      4.此时x,y必定只差一步就相会了 则 LCA=fa[x] (x的父结点)

                                                                                                                                                                   -----《算法竞赛》

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<vector>
     4 #include<cmath>
     5 #define M 40010
     6 #define go(i,a,b) for(register int i=a;i<=b;i++)
     7 #define go1(i,a,b) for(register int i=a;i>=b;i--)
     8 using namespace std;
     9 int read()
    10 {
    11   int x=0,y=1; char c; c=getchar();
    12   while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();}
    13   while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    14   return x*y;
    15 }
    16 int b[M],d[M],f[M][30],dis[M],T,m,n,tt,t;
    17 struct node1 {int v,w,n;} a[M*2];
    18 void add(int u,int v,int w) {a[++tt].n=b[u];a[tt].v=v;a[tt].w=w;b[u]=tt;}
    19 void dfs(int u)
    20 {
    21   int v,w;
    22   for(int i=b[u];i;i=a[i].n)
    23     {
    24       v=a[i].v;w=a[i].w;
    25       if(v==f[u][0]) continue ;
    26       f[v][0]=u;
    27       dis[v]=dis[u]+w;
    28       d[v]=d[u]+1;
    29       go(j,1,t) f[v][j]=f[f[v][j-1]][j-1];
    30       dfs(v);
    31     }
    32 }
    33 int lca(int u,int v)
    34 {
    35   if(d[u]>d[v]) swap(u,v);
    36   go1(i,t,0) if(d[f[v][i]]>=d[u]) v=f[v][i];
    37   if(u==v) return u;
    38   go1(i,t,1) if(f[u][i]!=f[v][i]) {u=f[u][i];v=f[v][i];}
    39   return f[u][0];
    40 }
    41 int main()
    42 {
    43   T=read();
    44   while(T--)
    45     {
    46       int u,v,w;
    47       n=read();m=read();t=(int)(log(n)/log(2))+1;
    48       tt=0; go(i,1,n) {dis[i]=0;d[i]=0;b[i]=0;}
    49       go(i,1,n-1) {u=read();v=read();w=read();add(u,v,w);add(v,u,w);}
    50       d[1]=1;dfs(1);
    51       go(i,1,m)
    52     {u=read();v=read();printf("%d
    ",dis[u]+dis[v]-2*dis[lca(u,v)]);}
    53     }
    54   return 0;
    55 }
    View Code

     Tarjan求LCA

    算法本质是使用并查集对“向上标记法”的优化。离线算法。复杂度为O(m+n)。

                                                                                                                                                                   -----《算法竞赛》

        画图非常清晰明了啊

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<vector>
     4 #define M 40010
     5 #define go(i,a,b) for(register int i=a;i<=b;i++)
     6 using namespace std;
     7 int read()
     8 {
     9   int x=0,y=1; char c; c=getchar();
    10   while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();}
    11   while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    12   return x*y;
    13 }
    14 vector<int> q[M][2];
    15 int b[M],ans[M],dis[M],f[M],fa[M];
    16 int tt,n,m,T;
    17 struct node1 {int v,w,n;} a[M*2];
    18 void add(int u,int v,int w) {a[++tt].n=b[u];a[tt].v=v;a[tt].w=w;b[u]=tt;}
    19 int find(int x) {if(fa[x]==x) return x; return fa[x]=find(fa[x]);}
    20 void tarjan(int u)
    21 {
    22   f[u]=1;int v,w,id;
    23   for(int i=b[u];i;i=a[i].n)
    24     {
    25       v=a[i].v;w=a[i].w;
    26       if(f[v]) continue ;
    27       dis[v]=dis[u]+w;
    28       tarjan(v);
    29       fa[v]=u;
    30     }
    31   for(int i=0;i<q[u][0].size();i++)
    32     {
    33       v=q[u][0][i];id=q[u][1][i];
    34       if(f[v]==2)
    35     {ans[id]=dis[u]+dis[v]-2*dis[find(v)];}
    36     }
    37   f[u]=2;
    38 }
    39 void init()
    40 {
    41   tt=0;
    42   go(i,1,n)
    43     {
    44       fa[i]=i;q[i][1].clear();q[i][2].clear();dis[i]=0;f[i]=0;b[i]=0;
    45     }
    46 }
    47 int main()
    48 {
    49   T=read();
    50   while(T--)
    51     {
    52       n=read();m=read();  int u,v,w;
    53       init();;
    54       go(i,1,n-1)
    55     {u=read();v=read();w=read();add(u,v,w);add(v,u,w);}
    56       go(i,1,m)
    57     {
    58       u=read();v=read();
    59       q[u][0].push_back(v);q[v][0].push_back(u);
    60       q[u][1].push_back(i);q[v][1].push_back(i);
    61     }
    62       tarjan(1);
    63       go(i,1,m) printf("%d
    ",ans[i]);
    64     }
    65   return 0;
    66 }
    View Code
    光伴随的阴影
  • 相关阅读:
    atitit.session的原理以及设计 java php实现的异同
    atitit.破解 拦截 绕过 网站 手机 短信 验证码 之自动获取手机短信方式 attilax 总结
    java softReference 详解
    android开发:TextView中android:autoLink属性的作用
    抽象类和接口的简单差别
    android一个简单的线程实例
    Java 批注
    最简单的菜单操作
    AsyncTask的参数介绍
    (转)android中ListView在划屏到底部的时候动态添加ListView的Item实现
  • 原文地址:https://www.cnblogs.com/forward777/p/10140617.html
Copyright © 2020-2023  润新知