【模板】最近公共祖先(LCA)
来源:互联网 发布:启明星bsc软件 编辑:程序博客网 时间:2024/06/05 02:05
题自洛谷
题目描述
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入输出格式
输入格式:
第一行包含三个正整数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
LCA的两种常见算法就是树上倍增和tarjan
两者的区别就是前者是在线算法后者是在线算法
(一个直接出答案一个是最后一起出答案)
这里都提供一下吧,但是树上倍增的代码不一定对(洛谷上只有30分)
看了下别人的题解说是卡常,但是懒得去改了
tarjan
#include<cstdio>using namespace std;const int M=2000005,N=1000005; //数据要多开一倍int fa[N],head[N],qhead[N],vis[N];struct edge{ int to,next;}edge[N];struct qedge{ int to,next,ans;}q[M];int read(){ int sum=0; char ch=getchar(); while(ch>'9'||ch<'0') ch=getchar(); while(ch<='9'&&ch>='0') { sum=sum*10+ch-48; ch=getchar(); } return sum;}int cnt;void add(int x,int y){ edge[++cnt].to=y; edge[cnt].next=head[x]; head[x]=cnt; } void aadd(int x,int y,int z){ q[z].to=y; q[z].next=qhead[x]; qhead[x]=z;}int find(int x){ if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x];}void unity(int x,int y){ x=find(x),y=find(y); fa[y]=x;}void tarjan(int x){ vis[x]=1; for(int i=head[x];i;i=edge[i].next) { int to=edge[i].to; if(!vis[to]) { tarjan(to); unity(x,to); } } for(int i=qhead[x];i;i=q[i].next) { if(vis[q[i].to]==2) { q[i].ans=find(q[i].to); if(i%2)q[i+1].ans=q[i].ans; else q[i-1].ans=q[i].ans; } } vis[x]=2;}int main(){ int n=read(),m=read(),s=read(); for(int i=1;i<n;i++) { int x=read(),y=read(); add(y,x),add(x,y); fa[i]=i; } fa[n]=n; for(int i=1;i<=m;i++) { int x=read(),y=read(); aadd(x,y,i*2-1); aadd(y,x,i*2); } tarjan(s); for(int i=1;i<=n;i++) printf("%d\n",q[i*2].ans); return 0;}
倍增
#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;struct node{ int to,next;}e[1000005];int lca[30][600005],deep[600005],h[1000005];int n,m,t,root;void add(int u,int v){ e[++t].to=v; e[t].next=h[u]; h[u]=t;}int read(){ int sum=0; char ch=getchar(); while(ch>'9'||ch<'0') ch=getchar(); while(ch<='9'&&ch>='0') { sum=sum*10+ch-48; ch=getchar(); } return sum;}void dfs(int n,int f,int d){ lca[0][n]=f; deep[n]=d; for(int i=h[n];i!=-1;i=e[i].next) { if(e[i].to!=f) dfs(e[i].to,n,d+1); }}void init(){ dfs(root,-1,0); for(int k=0;k<t-1;k++) { for(int i=1;i<=n;i++) { if(lca[k][i]<0) lca[k+1][i]=-1; else lca[k+1][i]=lca[k][lca[k][i]]; } }}int LCA(int x,int y){ if(deep[x]>deep[y]) swap(x,y); for(int i=0;i<t;i++) { if(((deep[y]-deep[x])>>i)&1) y=lca[i][y]; } if(x==y) return x; for(int i=t;i>=0;i--) { if(lca[i][x]!=lca[i][y]) { x=lca[i][x]; y=lca[i][y]; } } return lca[0][x];}int main(){ int x,y; memset(h,-1,sizeof(h)); n=read(),m=read(),root=read(); t=int(log10(n)/log10(2))+1; for(int i=1;i<n;i++) { x=read();y=read(); add(x,y);add(y,x); } init(); for (int i=1;i<=m;i++) { x=read();y=read(); printf("%d\n",LCA(x,y)); } return 0;}
更新 诈尸(倍增 v2.0)
还是要用BFS初始化好一些啊
毕竟时间上BFS还是保守一点的,这次倍增也能过洛谷所有点了
下面贴代码
#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;struct node{ int to,next;}e[1000005];int lca[500005][25],deep[600005],h[500005],q[500005];bool vis[500005];int n,m,t,root;void add(int u,int v){ e[++t].to=v; e[t].next=h[u]; h[u]=t;}int read(){ int sum=0; char ch=getchar(); while(ch>'9'||ch<'0') ch=getchar(); while(ch<='9'&&ch>='0') { sum=sum*10+ch-48; ch=getchar(); } return sum;}void bfs(){ int hd=0,tl=1; q[1]=root; vis[root]=1; deep[root]=1; lca[root][0]=1; while(hd<tl) { int u=q[++hd]; for(int i=1;i<=20;i++) lca[u][i]=lca[lca[u][i-1]][i-1]; for(int i=h[u];i!=0;i=e[i].next) { int v=e[i].to; if(vis[v]==0) { vis[v]=1; q[++tl]=v; deep[v]=deep[u]+1; lca[v][0]=u; } } }}int LCA(int x,int y){ if(deep[x]<deep[y]) swap(x,y); for(int i=20;i>=0;i--) if(deep[y]+(1<<i)<=deep[x]) x=lca[x][i]; if(x==y) return x; for(int i=20;i>=0;i--) if(lca[x][i]!=lca[y][i]) { x=lca[x][i]; y=lca[y][i]; } return lca[x][0];}int main(){ int x,y; n=read(),m=read(),root=read(); for(int i=1;i<n;i++) { x=read();y=read(); add(x,y);add(y,x); } bfs(); for (int i=1;i<=m;i++) { x=read();y=read(); printf("%d\n",LCA(x,y)); } return 0;}
阅读全文
0 0
- LCA----【模板】最近公共祖先(LCA)
- 【模板】最近公共祖先(LCA)
- 【模板】最近公共祖先(LCA)
- P3379 【模板】最近公共祖先(LCA)
- 【模板】【图论】最近公共祖先(LCA)
- 【模板】最近公共祖先(LCA)
- 最近公共祖先LCA【模板】
- [模板]最近公共祖先LCA
- 【模板】lca 最近公共祖先
- LCA(最近公共祖先)
- 【最近公共祖先(LCA)】
- 最近公共祖先(LCA)
- 最近公共祖先(LCA)
- LCA(最近公共祖先)
- 【讲解+模板】最近公共祖先(LCA)(倍增)
- 洛谷 P3379 【模板】最近公共祖先(LCA)
- lca(最近公共祖先)倍增模板【pascal】
- 最近公共祖先LCA模板(Tarjan/RMQ)
- POJ 1740 A New Stone Game (总结发现规律)
- cvpr2015的face Alignment 文章笔记
- 设计模式之单例模式 最快入门
- 【JavaScript】又一神器框架:linq.js
- C++中的类所占内存空间总结
- 【模板】最近公共祖先(LCA)
- nginx rtmp 包在wireshark中的体现
- python 编程从入门到实践11章 测试代码 11.2测试类11.2.2 修改
- Hessian 源码简单分析
- Android SystemProperties
- 在linux服务器上安装Gradle
- spring添加定时任务
- POJ
- 2.html结构和sublime快捷键