P3379 【模板】最近公共祖先(LCA)
题目描述
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入格式
第一行包含三个正整数 N,M,SN,M,S,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来 N-1N−1 行每行包含两个正整数 x, yx,y,表示 xx 结点和 yy 结点之间有一条直接连接的边(数据保证可以构成树)。
接下来 MM 行每行包含两个正整数 a, ba,b,表示询问 aa 结点和 bb 结点的最近公共祖先。
输出格式
输出包含 MM 行,每行包含一个正整数,依次为每一个询问的结果。
输入输出样例
输入 #1
1 2 3 4 5 6 7 8 9 10
| 5 5 4 3 1 2 4 5 1 1 4 2 4 3 2 3 5 1 2 4 5
|
输出 #1
lca 模板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| const int INF=0x3f3f3f3f; const int MAX=500000+10; int n,m,s,x,y; int anc[MAX][25],l[MAX]; bool vis[MAX]; struct edge{ int to,next; }e[MAX*2]; int head[MAX],tot=0; void addedge(int u,int v){ e[tot].to=v; e[tot].next=head[u]; head[u]=tot++; } void dfs(int u){ vis[u]=1; for(int i=head[u];i!=-1;i=e[i].next){ int v = e[i].to; if(vis[v]) continue; l[v]=l[u]+1; anc[v][0]=u; fi(j,1,15) anc[v][j]=-1; dfs(v); } } void pre(){ fi(j,1,21) fi(i,1,n+1) if(anc[i][j-1]!=-1) anc[i][j]=anc[anc[i][j-1]][j-1]; } int lca(int p,int q){ if(l[p]<l[q]) swap(p,q); for(int i=15;i>=0;i--) if(l[anc[p][i]]>=l[q]) p=anc[p][i]; if(p==q) return p; for(int i=15;i>=0;i--) if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i]){ p=anc[p][i];q=anc[q][i]; } return anc[p][0]; } int main(){ freopen("in","r",stdin); mem(head,-1); sf(n);sf(m);sf(s); fi(i,0,n-1){ sf(x);sf(y); addedge(x,y); addedge(y,x); } l[s]=1;anc[s][0]=-1; dfs(s);pre(); while(m--){ sf(x);sf(y); pf(lca(x,y));pfc("\n"); } return 0; }
|