1. 程式人生 > 實用技巧 >【UOJ 226】最近公共祖先

【UOJ 226】最近公共祖先

【題目描述】:

有根樹在電腦科學工程領域是一個人人熟知的資料結構型別。下面是一個例子。

8->(1,4,5);1->(13,14);4->(6,10);5->(9);6->(7,15);10->(2,11,16);16->(3,12);

在這個圖中,每個點都是由{1, 2,...,16}中的某個數字標記的。8號點是樹的根。如果x號點在y號點到根的路徑上,則x是y的祖先。比如4是16的祖先,10也是。事實上,8,4,10,16都是16的祖先。記住,一個節點本身就是自己的祖先。再比如8,4,6,7是7的祖先。

如果x既是y的祖先也是z的祖先則稱x是y和z公共祖先。也就是說8和4都是16和7的公共祖先。

如果x在y和z的所有公共祖先中距離y和z最近,則x是y和z的最近公共祖先。也就是說4是16和7的最近公共祖先而不是8,因為4比8更近。

再舉一些例子:節點2和3的最近共同祖先是節點10,節點6和13的最近共同祖先是節點8,節點4和12的最近共同祖先是節點4。在最後一個例子中,如果Y是Z的祖先,那麼Y和Z的最近共同祖先是Y。

編寫一個程式,找出樹中兩個不同節點的最近共同祖先。

【輸入描述】:

第一行,N和M表示節點數和詢問數,節點編號1至N;

以下N-1行,每行兩個整數a和b,表示a是b的父親節點;

之後M行,每行兩個不相同的數,表示詢問它們的最近共同祖先。

【輸出描述】:

M行,每行一個數表示對應的詢問結果。

【樣例輸入】:

16 1
1 14
8 5
10 16
5 9
4 6
8 4
4 10
1 13
6 15
10 11
6 7
10 2
16 3
8 1
16 12
16 7

【樣例輸出】:

4

【時間限制、資料範圍及描述】:

時間:1s 空間:256M

對於 40%的資料:1<=N,M<=3000

對於 100%的資料:1<=N,M<=2×10^5

題解;Lca題目 為了練習用tarjan做了~

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include
<cstring> #include<algorithm> #include<bits/stdc++.h> typedef long long ll; using namespace std; const int N=500002; int yc,n,x,y,m,cnt,head[N]; struct node{ int to; int next; }e[N]; void add(int a,int b){ e[++cnt].to=b; e[cnt].next=head[a]; head[a]=cnt; } int ta[N],ti[N],son[N],sz[N],dep[N],fa[N],dfsc,top[N]; void dfs1(int u,int pa,int de){ son[u]=0; sz[u]=1; dep[u]=de; fa[u]=pa; for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(v==pa) continue; dfs1(v,u,de+1); sz[u]+=sz[v]; if(sz[v]>sz[son[u]]) son[u]=v; } } void dfs2(int u,int pa){ ti[u]=++dfsc; top[u]=pa; if(son[u]!=0) dfs2(son[u],pa); //else return; for(int i=head[u];i;i=e[i].next) if(e[i].to!=son[u] && e[i].to!=fa[u]) dfs2(e[i].to,e[i].to); } int lca(int x,int y){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); return x; } int main(){ scanf("%d %d",&n,&m); for(int i=1;i<n;i++) { scanf("%d %d",&x,&y); add(x,y); add(y,x); ta[y]=x; } for(int i=1;i<=n;i++) if(ta[i]==0) { yc=i; break; } dfs1(yc,yc,0); dfs2(yc,yc); for(int i=1;i<=m;i++) { scanf("%d %d",&x,&y); printf("%d\n",lca(x,y)); } return 0; }