树上倍增求LCA

大概思想就是,节点$i$的第$2^{j}$个父节点是他第$2^{j-1}$个父亲的第$2^{j-1}$个父亲

然后可以$O(nlogn)$时间内解决……

没了?

 1 //fa[i][j]表示i的第2^j个父节点 
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 using namespace std;
 7 struct edge{
 8     int v,next;
 9 }a[100001];
10 int n,q,u,v,rt,tot=0,head[100001],fa[100001][31],dep[100001];
11 bool vis[100001];
12 void add(int u,int v){
13     a[++tot].v=v;
14     a[tot].next=head[u];
15     head[u]=tot;
16 }
17 void cal_dep(int u){
18     vis[u]=true;
19     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
20         int v=a[tmp].v;
21         if(!vis[v]){
22             dep[v]=dep[u]+1;
23             cal_dep(v);
24         }
25     }
26 }
27 void cal(){
28     for(int j=1;j<=30;j++){
29         for(int i=1;i<=n;i++){
30             fa[i][j]=fa[fa[i][j-1]][j-1];
31         }
32     }
33 }
34 int lca(int x,int y){
35     if(dep[x]<dep[y]){
36         swap(x,y);
37     }
38     int s=dep[x]-dep[y];
39     for(int i=0;i<30;i++){
40         if((1<<i)&s)x=fa[x][i];
41     } 
42     if(x==y)return x;
43     for(int i=29;i>=0;i--){
44         if(fa[x][i]!=fa[y][i]){
45             x=fa[x][i];
46             y=fa[y][i];
47         }
48     }
49     return fa[x][0];
50 }
51 int main(){
52     memset(head,-1,sizeof(head));
53     memset(fa,0,sizeof(fa));
54     memset(dep,0,sizeof(dep));
55     memset(vis,0,sizeof(vis));
56     scanf("%d%d",&n,&q);
57     for(int i=1;i<n;i++){
58         scanf("%d%d",&u,&v);
59         add(u,v);  
60         fa[v][0]=u;
61         //if(!fa[u][0])rt=u;
62     }
63     dep[1]=1;
64     cal_dep(1);
65     cal();
66     for(int i=1;i<=q;i++){
67         scanf("%d%d",&u,&v);
68         printf("%d\n",lca(u,v));
69     }
70     return 0;
71 }
72 /*
73 16 4
74 1 2
75 1 3
76 2 4
77 2 5
78 2 6
79 3 7
80 4 8
81 4 9
82 5 10
83 7 11
84 7 12
85 10 13
86 10 14
87 10 15
88 12 16
89 4 7
90 9 16
91 11 16
92 15 8
93 ------
94 1
95 1
96 7
97 2
98 */

猜你喜欢

转载自www.cnblogs.com/dcdcbigbig/p/8952821.html