洛谷 P3379 【模板】最近公共祖先(LCA,树链剖分)

传送门


 

解题思路

求LCA一般可以用倍增、树链剖分、tarjan算法解决。

这里只介绍树剖。

先处理出每一条链的链顶,然后对于每两个要求的点,判断是否在同一条链上。如果在,那么深度较浅的点就是LCA。

如果不在同一条链上,就比较两个所在链的链顶的深度,把链顶深度较低的点跳到链顶的父亲(这样就保证有答案了)。

时间复杂度:O(mlogn)。

AC代码

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<cstring>
 6 using namespace std;
 7 const int maxn=500005;
 8 int n,m,s,siz[maxn],cnt,tp[maxn],dep[maxn],p[maxn],son[maxn],f[maxn];
 9 struct node{
10     int v,next;
11 }e[maxn*2];
12 void insert(int u,int v){
13     cnt++;
14     e[cnt].next=p[u];
15     e[cnt].v=v;
16     p[u]=cnt;
17 }
18 void dfs1(int u,int fa,int deep){
19     int maxsize=0,maxson=0;
20     f[u]=fa;
21     siz[u]=1;
22     dep[u]=deep;
23     for(int i=p[u];i!=-1;i=e[i].next){
24         int v=e[i].v;
25         if(v==fa) continue;
26         dfs1(v,u,deep+1);
27         siz[u]+=siz[v];
28         if(siz[v]>maxsize){
29             maxsize=siz[v];
30             maxson=v;
31         }
32     }
33     son[u]=maxson;
34 }
35 void dfs2(int u,int fa,int top){
36     tp[u]=top;
37     if(son[u]){
38         dfs2(son[u],u,top); 
39         for(int i=p[u];i!=-1;i=e[i].next){
40             int v=e[i].v;
41             if(v==fa||v==son[u]) continue;
42             dfs2(v,u,v);
43         }
44     }
45 }
46 int main()
47 {
48     memset(p,-1,sizeof(p));
49     cin>>n>>m>>s;
50     for(int i=1;i<n;i++){
51         int u,v;
52         scanf("%d%d",&u,&v);
53         insert(u,v);
54         insert(v,u);
55     }
56     dfs1(s,-1,1);
57     dfs2(s,-1,s);
58 //    for(int i=1;i<=n;i++) cout<<tp[i]<<" ";
59     for(int i=1;i<=m;i++){
60         int a,b;
61         scanf("%d%d",&a,&b);
62         while(tp[a]!=tp[b]){
63             if(dep[tp[a]]>dep[tp[b]]) a=f[tp[a]];
64             else b=f[tp[b]];
65         }
66         if(dep[a]>dep[b]) cout<<b<<endl;
67         else cout<<a<<endl;
68     }
69     return 0;
70 }

 

posted @ 2020-09-05 21:31  尹昱钦  阅读(176)  评论(0编辑  收藏  举报