模板LCA(最近公共祖先)的各种写法(施工中)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板LCA(最近公共祖先)的各种写法(施工中)相关的知识,希望对你有一定的参考价值。

以洛谷模板题(P3379)为例。

题目描述

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

输入输出格式

输入格式:

 

第一行包含三个正整数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。

 

 

首先是离线(需要事先知道所有询问)的Tarjan算法(dfs+并查集)。

Tarjan的学习:http://www.cnblogs.com/JVxie/p/4854719.html

下面是代码:

 1 #include <bits/stdc++.h>
 2 #define M 1001000
 3 using namespace std;
 4 
 5 int read() {
 6     int x=0, w=1;
 7     char ch=0;
 8     while (ch<0 || ch>9) {
 9         if (ch==-)
10             w=-1;
11         ch=getchar();
12     }
13     while (ch>=0 && ch<=9)
14         x=(x<<3)+(x<<1)+ch-0, ch=getchar();
15     return x*w;
16 }
17 
18 void write(int x) {
19     if (x>=10)
20         write(x/10);
21     putchar(x%10+0);
22 }
23 
24 int n,q,cnt1,cnt2, root;
25 int ans[M],head[M],qhead[M],fa[M];
26 bool vis[M];
27 
28 struct data {
29     int to,next,v;
30 }e[M],qe[M];
31 
32 void add(int u,int v){
33     e[cnt1].to=v, e[cnt1].next=head[u], head[u]=cnt1++;
34 }
35 
36 void qadd(int u,int v){
37     qe[cnt2].to=v, qe[cnt2].next=qhead[u], qhead[u]=cnt2++;
38 }
39 
40 int find(int x){
41     if(fa[x]!=x)
42         fa[x]=find(fa[x]);
43     return fa[x];
44 }
45 
46 void Tarjan(int x){
47     fa[x]=x;
48     vis[x]=1;
49     for(int i=head[x];i!=-1;i=e[i].next)
50         if(!vis[e[i].to]){
51             Tarjan(e[i].to);
52             fa[e[i].to]=x;
53         }
54     for(int i=qhead[x];i!=-1;i=qe[i].next)
55         if(vis[qe[i].to]){
56             qe[i].v=find(qe[i].to);
57             qe[i^1].v=qe[i].v;
58         }
59 }
60 
61 int main(){
62     scanf("%d%d%d",&n, &q, &root);
63     memset(head, -1, sizeof(head));
64     memset(qhead, -1, sizeof(qhead));
65     int u,v;
66     for(int i=1;i<n;i++){
67         u=read(); v=read();
68         add(u,v); add(v, u);
69     }
70     for(int i=1;i<=q;i++){
71         u=read(); v=read();
72         qadd(u,v); qadd(v,u);
73     }
74     Tarjan(root);
75     for(int i=0;i<=2*(q-1);i++)
76       if(i%2==0) {
77           write(qe[i].v);
78           printf("\\n");
79       }
80     return 0;
81 }

 

然后是在线的基于dp的ST算法。

ST算法的学习:http://blog.csdn.net/y990041769/article/details/40887469

代码有时间再补吧..家长不让用电脑了..



以上是关于模板LCA(最近公共祖先)的各种写法(施工中)的主要内容,如果未能解决你的问题,请参考以下文章

模板LCA

P3379 模板最近公共祖先(LCA)

P3379 模板最近公共祖先(LCA)(倍增LCA)

P3379 模板最近公共祖先(LCA)

最近公共祖先 LCA 递归非递归

Luogu P3379 模板最近公共祖先(LCA)