标签:邻接表 pre swap oid 指定 lin 树根 输出 接下来
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入格式:
第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。
接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。
输出格式:
输出包含M行,每行包含一个正整数,依次为每一个询问的结果。
结构体 来存 邻接表
d数组表示 这个点 的 深度
f 数组 表示 i 向上跳 2^k 步的点
lg 数组 应该是个 常数优化
CODE:
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 int n,m,s,num; 5 int d[500001],f[21][500001],lg[500001]; 6 int lin[1000001]; 7 struct qwq{ 8 int t,next; 9 }zh[1000001]; 10 void add(int x,int y) 11 { 12 num++; 13 zh[num].t=y; 14 zh[num].next=lin[x]; 15 lin[x]=num; 16 } 17 void dfs(int x,int y) 18 { 19 d[x]=d[y]+1; 20 f[0][x]=y; 21 for(int k=1;(1<<k)<=d[x];k++) 22 f[k][x]=f[k-1][f[k-1][x]];//f表示i向上跳2^k步的点 23 for(int i=lin[x];i;i=zh[i].next) 24 if(zh[i].t!=y) 25 dfs(zh[i].t,x); 26 } 27 int LCA(int u,int v) 28 { 29 if(d[u]<d[v])//d表示这个点的深度 30 swap(u,v); 31 while(d[u]>d[v]) 32 u=f[lg[d[u]-d[v]]-1][u]; 33 if(u==v) 34 return u; 35 for(int k=lg[d[u]]-1;k>=0;k--) 36 { 37 if(f[k][u]!=f[k][v]) 38 u=f[k][u],v=f[k][v]; 39 } 40 return f[0][u]; 41 } 42 int main() 43 { 44 scanf("%d%d%d",&n,&m,&s); 45 for(int i=1;i<n;i++) 46 { 47 int x,y; 48 scanf("%d%d",&x,&y); 49 add(x,y),add(y,x); 50 } 51 dfs(s,0); 52 for(int i=1;i<=n;i++) 53 lg[i]=lg[i-1]+(1<<lg[i-1]==i);//常数优化? 54 for(int i=1;i<=m;i++) 55 { 56 int x,y; 57 scanf("%d%d",&x,&y); 58 printf("%d\n",LCA(x,y)); 59 } 60 return 0; 61 }
标签:邻接表 pre swap oid 指定 lin 树根 输出 接下来
原文地址:https://www.cnblogs.com/-Wind-/p/10344010.html