在线查询树上最近公共祖先模板
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在线查询树上最近公共祖先模板相关的知识,希望对你有一定的参考价值。
在线查询树上最近公共祖先
标准题目
第一行有2个整数n和q:n代表树的结点数量,q代表询问的次数接下来n-1行每行两个整数u和v,表示结点u到结点v有一条边。
然后给出q组询问,每组询问由两个整数a和b构成,询问节点a和b的最近公共祖先。
样例数据
input:
8 3
1 3
1 2
3 4
3 5
3 6
2 7
2 8
4 5
6 7
5 8
output:
3
1
1
代码
1. 邻接表建图
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 using namespace std; 7 const int lim=100000000; 8 const int maxn=600010; 9 struct point { 10 int to; 11 int nxt; 12 } edge[maxn*2]; 13 int n,Q,tot=0; 14 int dep[maxn]= {0},f[20][maxn]; 15 bool vis[maxn]; 16 int head[maxn]; 17 18 void add(int u,int v) { 19 tot++; 20 edge[tot].to=v; 21 edge[tot].nxt=head[u]; 22 head[u]=tot; 23 } 24 25 26 int Lca(int x,int y) { //lca 27 int temp,co=0,lca; 28 int tx=x,ty=y; 29 if(dep[tx]>dep[ty]) swap(tx,ty); 30 temp=dep[ty]-dep[tx]; 31 while(temp) { 32 if(temp&1) ty=f[co][ty]; 33 temp>>=1; 34 co++; 35 } 36 if(tx==ty) return tx; 37 else { 38 for(int j=19; j+1; j--) { 39 if((1<<j)>dep[tx]) continue; 40 if(f[j][tx]!=f[j][ty]) { 41 tx=f[j][tx]; 42 ty=f[j][ty]; 43 } 44 } 45 lca=f[0][tx]; 46 } 47 return lca; 48 } 49 inline void bfs() { 50 queue<int> q; 51 vis[1]=1; 52 dep[1]=0; 53 q.push(1); 54 while(!q.empty()) { //宽搜处理dep和f[0][i] (父节点) 55 int tt=q.front(); 56 q.pop(); 57 for(int i=head[tt]; i; i=edge[i].nxt) { 58 int v=edge[i].to; 59 if(!vis[v]) { 60 vis[v]=1; 61 q.push(v); 62 dep[v]=dep[tt]+1; 63 f[0][v]=tt; 64 } 65 } 66 } 67 } 68 int main() { 69 memset(head,0,sizeof(head)); 70 cin>>n>>Q; 71 for(int i=1; i<=n-1; i++) { 72 int a,b; 73 cin>>a>>b; 74 add(a,b);//双向建图 75 add(b,a); 76 } 77 78 bfs(); 79 for(int j=1; j<20; j++) //倍增 80 for(int i=1; i<=n; i++) 81 if(dep[i]>=(1<<j)) 82 f[j][i]=f[j-1][f[j-1][i]]; 83 while(Q--) { 84 int a,b,lca; 85 cin>>a>>b; 86 lca=Lca(a,b); 87 cout<<lca<<endl; 88 } 89 90 return 0; 91 }
2. Vector建图
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int maxn=600010; int n,Q,tot=0; int depth[maxn]= {0},f[20][maxn]; bool vis[maxn]; int head[maxn]; vector<int> edge[maxn]; void add(int u,int v) { edge[u].push_back(v); } int Lca(int x,int y) { //lca int temp,co=0,lca; int tx=x,ty=y; if(depth[tx]>depth[ty]) swap(tx,ty); temp=depth[ty]-depth[tx]; while(temp) { if(temp&1) ty=f[co][ty]; temp>>=1; co++; } if(tx==ty) return tx; else { for(int j=19; j+1; j--) { if((1<<j)>depth[tx]) continue; if(f[j][tx]!=f[j][ty]) { tx=f[j][tx]; ty=f[j][ty]; } } lca=f[0][tx]; } return lca; } inline void bfs() { queue<int> q; vis[1]=1; depth[1]=0; q.push(1); while(!q.empty()) { //宽搜处理depth和f[0][i] int now=q.front(); q.pop(); int len=edge[now].size(); for(int i=0; i<len; i++) { int v=edge[now][i]; if(!vis[v]) { vis[v]=1; q.push(v); depth[v]=depth[now]+1; f[0][v]=now; } } } } int main() { memset(head,0,sizeof(head)); cin>>n>>Q; for(int i=1; i<=n-1; i++) { int a,b; cin>>a>>b; add(a,b);//双向建图 add(b,a); } bfs(); for(int j=1; j<20; j++) //倍增 for(int i=1; i<=n; i++) if(depth[i]>=(1<<j)) f[j][i]=f[j-1][f[j-1][i]]; while(Q--) { int a,b,lca; cin>>a>>b; lca=Lca(a,b); cout<<lca<<endl; } return 0; }
以上是关于在线查询树上最近公共祖先模板的主要内容,如果未能解决你的问题,请参考以下文章