码迷,mamicode.com
首页 > 其他好文 > 详细

[模板]LCA全集

时间:2019-10-22 22:22:40      阅读:109      评论:0      收藏:0      [点我收藏+]

标签:target   输入输出   set   struct   swa   main   space   前向星   names   

如题:

LCA(倍增):

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<queue>
 7 using namespace std;
 8 int n,m,s,tot=0;
 9 const int N=500005,M=1000005;
10 int head[N],to[M],nxt[M];
11 int depth[N],fa[N][22],lg[N];
12 
13 void add(int x,int y)
14 {
15     to[++tot]=y;
16     nxt[tot]=head[x];
17     head[x]=tot;
18     return ;
19 }
20 
21 void dfs(int x,int y)
22 {
23     depth[x]=depth[y]+1;
24     fa[x][0]=y;
25     for(int i=1;(1<<i)<=depth[x];i++)
26         fa[x][i]=fa[fa[x][i-1]][i-1];
27     for(int i=head[x];i;i=nxt[i])
28         if(to[i]!=y)
29             dfs(to[i],x);
30     return ;
31 }
32 
33 int LCA(int x,int y)
34 {
35     if(depth[x]<depth[y])
36         swap(x,y);
37     while(depth[x]>depth[y])
38         x=fa[x][lg[depth[x]-depth[y]]-1];
39     if(x==y)
40         return x;
41     for(int k=lg[depth[x]];k>=0;--k)
42         if(fa[x][k]!=fa[y][k])
43         {
44             x=fa[x][k];
45             y=fa[y][k];
46         }   
47     return fa[x][0];
48 }
49 
50 int main()
51 {
52     cin>>n>>m>>s;
53     for(int i=1;i<n;i++)
54     {
55         int x,y;
56         scanf("%d %d",&x,&y);
57         add(x,y);
58         add(y,x);
59     }
60     dfs(s,0);
61     for(int i=1;i<=n;++i)
62         lg[i]=lg[i-1]+(1<<lg[i-1]==i);
63     for(int i=1;i<=m;++i)
64     {
65         int x,y;
66         scanf("%d %d",&x,&y);
67         printf("%d",LCA(x,y));
68     }
69     return 0;
70 } 

LCA(Tarjan):

  1 #include <iostream>
  2 #include <cstdio>//标准输入输出 
  3 using namespace std;
  4 int n,m,s,cnt;//cnt为边计数器 
  5 int head[500005];//链式前向星 
  6 int qhead[500005];//链式前向星 (询问) 
  7 int f[500005];//并查集储存父结点
  8 int vis[500005];//判断是否访问过 
  9 int lca[1000005];//离线存储答案 
 10 
 11 struct edge
 12 {
 13     int nxt;
 14     int to;
 15     //int dis;边权值默认为 1 
 16 }e[1000005];//建议4倍 
 17 
 18 struct qedge
 19 {
 20     int nxt;
 21     int to;
 22     //int dis;
 23 }qe[1000005];//建议4倍 
 24 
 25 void add(int x,int y/*,int d*/)
 26 {
 27     e[++cnt].nxt=head[x];
 28     e[cnt].to=y;
 29     head[x]=cnt;
 30 }//链式前向星加边 
 31 
 32 void qadd(int x,int y)
 33 {
 34     qe[++cnt].nxt=qhead[x];
 35     qe[cnt].to=y;
 36     qhead[x]=cnt;
 37 }//链式前向星加边 (询问) 
 38 
 39 int find(int x)
 40 {
 41     return f[x]== x ? x : f[x] = find( f[x] );//路径压缩 
 42 }//“查 ” 
 43 
 44 void merge(int a,int b)
 45 {
 46     int fa=find(a),fb=find(b);
 47     if(fa==fb)
 48     return ;
 49     f[fa]=fb;
 50 }//“并 ” 
 51 
 52 void setup(int N)
 53 {
 54     for(int i=1;i<=N;i++)
 55     {
 56         f[i]=i;
 57     }
 58 }//初始化 
 59 
 60 void tarjan(int x)
 61 {
 62     cout<<"#访问节点:"<<x<<endl;
 63     vis[x]=1;//标记访问 
 64     for(int i=head[x];i;i=e[i].nxt)//遍历此子节点所有出边 
 65     {
 66         int v=e[i].to;
 67         if(!vis[v])//如下一节点未访问 
 68         {
 69             tarjan(v);//继续遍历 
 70             f[v]=x;//回溯时更新子节点祖先 
 71             if(v==11)
 72             {
 73                 cout<<"//"<<x<<" "<<f[11]<<endl;
 74             }
 75         }
 76     }
 77     for(int i=qhead[x];i;i=qe[i].nxt)//对于询问中有此点的询问组 
 78     {
 79         int qv=qe[i].to;
 80         if(vis[qv])//若另一询问节点已被遍历 
 81         {
 82             lca[i]=find(qv);//则对于这组询问,其LCA为另一询问节点最后一次更新的祖先 
 83             if(i%2)//对于正反两组相同询问  
 84                 lca[i+1]=lca[i];//若为正向的询问,下一组询问为此次询问的反向询问 ,询问结果相同 
 85             else
 86                 lca[i-1]=lca[i];//若为反向的询问,下一组询问为此次询问的正向询问 ,询问结果相同 
 87         }
 88     }
 89 }//DFS函数 
 90 
 91 int main()
 92 {
 93     cin>>n>>m>>s;
 94     for(int i=1;i<n;i++)
 95     {
 96         int a,b;
 97         cin>>a>>b;
 98         add(a,b);//无向图正反存边 
 99         add(b,a);
100     }
101     cnt=0;//懒得再加一个变量qcnt 
102     for(int i=1;i<=m;i++)
103     {
104         int a,b;
105         cin>>a>>b;
106         qadd(a,b);//储存正反询问 
107         qadd(b,a);//无向图正反存边 
108     }
109     setup(n);//初始化 
110     tarjan(s);//以s为根开始遍历 
111     for(int i=1;i<=m;i++)
112     {
113         printf("%d\n",lca[i*2]);//由于每组询问储存了两遍,所以输出时输出其中一组 
114     }
115     return 0;
116 }

LCA(RMQ):

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cmath>
  4 using namespace std;
  5 int n,m,s,cnt,tot;
  6 int head[1000005];
  7 int depth[1000005];
  8 int num[1000005];
  9 int rec[2000005][20];
 10 int st[2000005][20];
 11 int euler[1000005];
 12 int dp[1000005];//求节点深度 
 13 int wd[1000005];//求某一深度树的宽度 
 14 struct edge
 15 {
 16     int nxt;
 17     int to;边权值 
 18 }e[1000005];建议开4倍数组 
 19 
 20 
 21 
 22 void add(int x,int y)
 23 {
 24     e[++cnt].nxt=head[x];
 25     e[cnt].to=y;
 26     head[x]=cnt;
 27 }
 28 void dfs(int x,int dep)
 29 {
 30 
 31     num[x]=++tot;
 32     depth[tot]=dep;
 33     euler[tot]=x;
 34     dp[x]=max(dp[x],depth[tot]); 
 35     //cout<<"#访问节点:"<<x<<"   depth数组:"<<depth[tot]<<endl;
 36     for(int i=head[x];i;i=e[i].nxt)
 37     {
 38         int p=e[i].to;
 39         if(num[p]==0)
 40         {
 41             dfs(p,dep+1);
 42             euler[++tot]=x;
 43             depth[tot]=dep;
 44         }
 45     }
 46     return ;
 47 }
 48 
 49 void RMQ(int N)
 50 {
 51     for(int j=1;j<=(int)(log((double)N)/log(2.0));j++)
 52     {
 53         for(int i=1;i<=N;i++)
 54         {
 55             if(i+(1<<j)-1<=N)
 56             if(st[i][j-1]<st[i+(1<<(j-1))][j-1])
 57                 st[i][j]=st[i][j-1],rec[i][j]=rec[i][j-1];
 58             else 
 59                 st[i][j]=st[i+(1<<(j-1))][j-1],rec[i][j]=rec[i+(1<<(j-1))][j-1];
 60         }
 61     }
 62 }
 63 
 64 int search(int l,int r)
 65 {
 66     int k=(int)(log((double)(r-l+1))/log(2.0));
 67     if(st[l][k]<st[r-(1<<k)+1][k])
 68     return rec[l][k];
 69     else
 70     return rec[r-(1<<k)+1][k];
 71 }
 72 
 73 
 74 
 75 int main()
 76 {
 77     cin>>n>>m;
 78     for(int i=1;i<=n-1;i++)
 79     {
 80         int a,b;
 81         scanf("%d %d",&a,&b);
 82         add(a,b);
 83         add(b,a);
 84     }
 85     dfs(1,1);
 86     for(int i=1;i<=tot;i++)
 87     {
 88         st[i][0]=depth[i],rec[i][0]=euler[i];
 89     }
 90     RMQ(tot);
 91     /*
 92     int dcnt=0,maxx=0;
 93     for(int i=1;i<=n;i++)
 94     {
 95         wd[dp[i]]++;
 96     }
 97     for(int i=1;i<=n;i++)
 98     {
 99         if(wd[i]==0)
100         {
101             break;
102         }
103         dcnt++;
104     }
105     for(int i=1;i<=wcnt+1;i++)
106     {
107         maxx=max(maxx,wd[i]);
108     }
109     //求树深度dcnt/宽度 maxx
110     */
111     for(int i=1;i<=m;i++)
112     {
113         int l,r,fg=0;
114         scanf("%d %d",&l,&r);
115         if(num[l]>num[r])
116         {
117             swap(num[l],num[r]);
118             fg=1;
119         }
120         printf("%d\n",search(num[l],num[r]));
121         if(fg==1)
122         swap(num[l],num[r]);
123     }
124     return 0;
125 }

LCA(树链剖分):

  1 #include <iostream>
  2 #include <cstdio>
  3 using namespace std;
  4 int n,m,s,cnt;
  5 int head[500005];
  6 int son[500005];
  7 int depth[500005];
  8 int f[500005];
  9 int top[500005];
 10 struct edge
 11 {
 12     int nxt;
 13     int to;
 14     //int dis;
 15 }e[2000005];
 16 void add(int x,int y/*,int d*/)
 17 {
 18     e[++cnt].nxt=head[x];
 19     e[cnt].to=y;
 20     head[x]=cnt;    
 21 } 
 22 void dfs(int x)
 23 {
 24     son[x]=1;
 25     depth[x]=depth[f[x]]+1;
 26     for(int i=head[x];i;i=e[i].nxt)
 27     {
 28         int p=e[i].to;
 29         if(f[x]!=p)
 30         {
 31             f[p]=x;
 32             dfs(p);
 33             son[x]+=son[p];
 34         }    
 35     }
 36 }
 37 void dsf(int x)
 38 {
 39     int t=0;
 40     if(!top[x])
 41     top[x]=x;
 42     for(int i=head[x];i;i=e[i].nxt)
 43     {
 44         int p=e[i].to;
 45         if(p!=f[x]&&son[p]>son[t])
 46         t=p;
 47     }
 48     if(t)
 49     {
 50         top[t]=top[x];
 51         dsf(t);
 52     }
 53     for(int i=head[x];i;i=e[i].nxt)
 54     {
 55         int p=e[i].to;
 56         if(p!=f[x]&&t!=p)
 57             dsf(p);
 58     }
 59 }
 60 int search(int x,int y)
 61 {
 62     for(;top[x]!=top[y];)
 63     {
 64         if(depth[top[x]]<depth[top[y]])
 65         {
 66             swap(x,y);
 67         }
 68         x=f[top[x]];
 69     }
 70     if(depth[x]>depth[y])
 71     {
 72         swap(x,y);
 73     }
 74     return x;
 75 }
 76 
 77 void setup(int x)
 78 {
 79     for(int i=1;i<=x;i++)
 80     {
 81         f[x]=x;
 82     }
 83 }
 84 
 85 int main()
 86 {
 87     cin>>n>>m>>s;
 88     for(int i=1;i<=n-1;i++)
 89     {
 90         int a,b;
 91         scanf("%d%d",&a,&b);
 92         add(a,b);
 93         add(b,a);
 94     }
 95     setup(n);
 96     dfs(s);
 97     dsf(s);
 98     for(int i=1;i<=m;i++)
 99     {
100         int a,b;
101         scanf("%d %d",&a,&b);
102         printf("%d\n",search(a,b));
103     }
104     return 0;
105 }

原文地址:

tarjan

RMQ

-----2021届张若琛

[模板]LCA全集

标签:target   输入输出   set   struct   swa   main   space   前向星   names   

原文地址:https://www.cnblogs.com/btjzoi/p/11722792.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!