[Luogu] 模板题-最近公共祖先

树链剖分版本:

 1 #include<cstdio>
 2 #include<iostream>
 3 #define maxn 1000000
 4 using namespace std;
 5 
 6 int siz[maxn],fa[maxn],depth[maxn],son[maxn],top[maxn],n,m,s;
 7 
 8 struct edge{
 9     int from,v;
10 }e[maxn];
11 int tot,first[maxn];
12 void insert(int u,int v){
13     tot++; e[tot].from = first[u]; e[tot].v = v; first[u] = tot;
14 }
15 
16 void dfs(int now){
17     siz[now] = 1;
18     for(int i = first[now];i;i = e[i].from){
19         int v = e[i].v;
20         if(v != fa[now]){
21             fa[v] = now;
22             depth[v] = depth[now]+1;
23             dfs(v);
24             siz[now] += siz[v];
25             if(!son[now] || siz[v] > siz[son[now]])
26                 son[now] = v;
27         }
28     }
29 }
30 
31 void dfs2(int now,int t){
32     top[now] = t;
33     if(!son[now]) return;
34     dfs2(son[now],t);
35     for(int i = first[now];i;i = e[i].from){
36         int v = e[i].v;
37         if(v != fa[now] && v != son[now])
38             dfs2(v,v);
39     }
40 }
41 
42 int LCA(int u,int v){
43     if(depth[top[u]] < depth[top[v]]) swap(u,v);
44     while(top[u] != top[v]){
45         u = fa[top[u]];
46         if(depth[top[u]] < depth[top[v]]) swap(u,v);
47     }if(depth[u] < depth[v]) swap(u,v);
48     return v;
49 }
50 
51 int main(){
52     scanf("%d%d%d",&n,&m,&s);
53     
54     for(int i = 1;i < n;i++){
55         int x,y; scanf("%d%d",&x,&y);
56         insert(x,y); insert(y,x);
57     }depth[s] = 1; dfs(s); dfs2(s,s);
58     
59     while(m--){
60         int u,v;
61         scanf("%d%d",&u,&v);
62         printf("%d\n",LCA(u,v));
63     }
64     
65     return 0;
66 }
链剖据说log n?

Tarjan版本:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #define maxn 500005
 5 using namespace std;
 6 
 7 struct edge{
 8     int from,u,v,ans,order;
 9 }e[maxn*2+5],e1[maxn*2+5];
10 
11 int pre[maxn];
12 int find(int x){
13     if(!pre[x]) return x;
14     else{
15         pre[x] = find(pre[x]);
16         return pre[x];
17     }
18 }
19 
20 bool book[maxn];
21 int tot,tot1,first1[maxn],first[maxn],n,m,s;
22 void insert(int u,int v){
23     tot++;
24     e[tot].from = first[u];
25     e[tot].v = v;
26     e[tot].u = u;
27     first[u] = tot;
28 }
29 
30 void insert1(int u,int v,int i){
31     tot1++;
32     e1[tot1].order = i;
33     e1[tot1].from = first1[u];
34     e1[tot1].u = u;
35     e1[tot1].v = v;
36     first1[u] = tot1;
37 }
38 
39 bool cmp(const edge &a,const edge &b){
40     return a.order < b.order;
41 }
42 
43 void Tarjan(int now,int father){
44     for(int i = first[now];i;i = e[i].from){
45         int v = e[i].v;
46         if(v == father) continue;
47         Tarjan(v,now);
48         pre[find(v)] = find(now);
49         book[v] = true;
50     }
51     
52     for(int i = first1[now];i;i = e1[i].from){
53         int v = e1[i].v;
54         if(v == father) continue;
55         if(book[v]){
56             e1[i].ans = find(v);
57         }
58     }
59 }
60 
61 int main(){
62     scanf("%d%d%d",&n,&m,&s);
63     for(int i = 1;i < n;i++){
64         int a,b;
65         scanf("%d%d",&a,&b);
66         insert(a,b);
67         insert(b,a);
68     }
69     
70     for(int i = 1;i <= m;i++){
71         int a,b;
72         scanf("%d%d",&a,&b);
73         insert1(a,b,i);
74         insert1(b,a,i);
75     }
76     
77     Tarjan(s,-1);
78     
79     sort(e1+1,e1+1+tot1,cmp);
80     
81     for(int i = 1;i <= tot1;i+=2){
82         if(!e1[i].ans) printf("%d\n",e1[i+1].ans);
83         else printf("%d\n",e1[i].ans);
84     }
85     
86     return 0;
87 }
用邻接表顺便储存询问

 

posted @ 2017-09-03 23:21  Leviaton  阅读(185)  评论(0编辑  收藏  举报