洛谷 P3379 【模板】最近公共祖先(LCA)

题目描述

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

输入输出格式

输入格式:

第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。

接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

输出格式:

输出包含M行,每行包含一个正整数,依次为每一个询问的结果。

输入输出样例

输入样例#1: 
5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5
输出样例#1: 
4
4
1
4
4

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=10,M<=10

对于70%的数据:N<=10000,M<=10000

对于100%的数据:N<=500000,M<=500000

样例说明:

该树结构如下:

第一次询问:2、4的最近公共祖先,故为4。

第二次询问:3、2的最近公共祖先,故为4。

第三次询问:3、5的最近公共祖先,故为1。

第四次询问:1、2的最近公共祖先,故为4。

第五次询问:4、5的最近公共祖先,故为4。

故输出依次为4、4、1、4、4。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 long long read()
 6 {
 7     long long x=0,f=1;
 8     char ch=getchar();
 9     while(ch>'9'||ch<'0')
10     {
11         if(ch=='-')
12             f=-1;
13         ch=getchar();
14     }
15     while(ch>='0'&&ch<='9')
16     {
17         x=x*10+ch-'0';
18         ch=getchar();
19     }
20     return x*f;
21 }
22 const int maxn=500005;
23 int n,m,s,k,a,b;
24 int head[maxn],d[maxn],p[maxn][21];
25 struct node
26 {
27     int v,next;
28 } e[maxn*2];
29 void add(int u,int v)
30 {
31     e[k].v=v;
32     e[k].next=head[u];
33     head[u]=k++;
34 }
35 void dfs(int u,int fa)
36 {
37     d[u]=d[fa]+1;
38     p[u][0]=fa;
39     for(int i=1; (1<<i)<=d[u]; i++)
40         p[u][i]=p[p[u][i-1]][i-1];
41     for(int i=head[u]; i!=-1; i=e[i].next)
42     {
43         int v=e[i].v;
44         if(v!=fa)
45             dfs(v,u);
46     }
47 }
48 int lca(int a,int b)
49 {
50     if(d[a]>d[b])
51         swap(a,b);
52     for(int i=20; i>=0; i--)
53         if(d[a]<=d[b]-(1<<i))
54             b=p[b][i];
55     if(a==b)
56         return a;
57     for(int i=20; i>=0; i--)
58     {
59         if(p[a][i]==p[b][i])
60             continue;
61         else
62             a=p[a][i],b=p[b][i];
63     }
64     return p[a][0];
65 }
66 int main()
67 {
68     memset(head,-1,sizeof(head));
69     n=read(),m=read(),s=read();
70     for(int i=1; i<n; i++)
71     {
72         a=read(),b=read();
73         add(a,b);
74         add(b,a);
75     }
76     dfs(s,0);
77     for(int i=1; i<=m; i++)
78     {
79         a=read(),b=read();
80         printf("%d
",lca(a,b));
81     }
82     return 0;
83 }
倍增求LCA
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=2e6+10;
 6 #define ls k<<1
 7 #define rs k<<1|1
 8 long long read()
 9 {
10     long long x=0,f=1;
11     char ch=getchar();
12     while(ch>'9'||ch<'0')
13     {
14         if(ch=='-')
15             f=-1;
16         ch=getchar();
17     }
18     while(ch>='0'&&ch<='9')
19     {
20         x=x*10+ch-'0';
21         ch=getchar();
22     }
23     return x*f;
24 }
25 struct node
26 {
27     int v,nxt;
28 } e[maxn];
29 int head[maxn],fa[maxn],deep[maxn],tot[maxn],son[maxn],top[maxn];
30 int num=1,cnt;
31 void add(int x,int y)
32 {
33     e[num].v=y;
34     e[num].nxt=head[x];
35     head[x]=num++;
36 }
37 int dfs1(int now,int f,int dep)
38 {
39     deep[now]=dep;
40     fa[now]=f;
41     tot[now]=1;
42     int maxson=-1;
43     for(int i=head[now]; i; i=e[i].nxt)
44     {
45         if(e[i].v==f)
46             continue;
47         tot[now]+=dfs1(e[i].v,now,dep+1);
48         if(tot[e[i].v]>maxson)
49             maxson=tot[e[i].v],son[now]=e[i].v;
50     }
51     return tot[now];
52 }
53 void dfs2(int now,int topf)
54 {
55     top[now]=topf;
56     if(!son[now])
57         return ;
58     dfs2(son[now],topf);
59     for(int i=head[now]; i; i=e[i].nxt)
60         if(e[i].v!=son[now]&&e[i].v!=fa[now])
61             dfs2(e[i].v,e[i].v);
62 }
63 int LCA(int x,int y)
64 {
65     while(top[x]!=top[y])
66     {
67         if(deep[top[x]]<deep[top[y]])
68             swap(x,y);
69         x=fa[top[x]];
70     }
71     if(deep[x]>deep[y])
72         swap(x,y);
73     return x;
74 }
75 int main()
76 {
77     memset(head,0,sizeof(head));
78     int n=read(),m=read(),root=read();
79     for(int i=1; i<=n-1; i++)
80     {
81         int x=read(),y=read();
82         add(x,y),add(y,x);
83     }
84     dfs1(root,0,1);
85     dfs2(root,root);
86     while(m--)
87     {
88         int x=read(),y=read();
89         printf("%d
",LCA(x,y));
90     }
91     return 0;
92 }
树链剖分求LCA
原文地址:https://www.cnblogs.com/liweilin/p/10198885.html