LCA(Tarjan)
阿新 • • 發佈:2019-03-14
name using ret namespace 鏈式前向星 line std getc tdi
時間復雜度:dfs為O(N)
,dfs過程中處理所有查詢對為O(M)
,總時間復雜度O(N+M)
#include<iostream> #include<cstdio> using namespace std; const int maxn=500010, maxm=500010; int N, M, S, tot, h[maxn], v[maxn], fa[maxn], p_tot, p_h[maxn]; struct edge{ int t, nxt; }E[maxn<<1]; //鏈式前向星,用於存儲樹 void add_edge(int u, int v){ E[++tot].t=v; E[tot].nxt=h[u]; h[u]=tot; } struct pair{ int s, t, lca, nxt;}P[maxm<<1]; //鏈式前向星,用於存儲查詢對 void add_pair(int s, int t){ P[++p_tot].t=t; P[p_tot].s=s; P[p_tot].nxt=p_h[s]; p_h[s]=p_tot; } inline int read() { int s=0, w=1; char ch=getchar(); while(ch<='0' || ch>'9') { if(ch=='-') w=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*w; } int getfa(int k){ return fa[k]==k ? k : fa[k]=getfa(fa[k]); } //並查集的查詢,帶路徑壓縮 void lca_tarjan(int x) { v[x]=1, fa[x]=x; //x點已訪問,設置其fa為自己,形成以x為根的一顆獨立子樹 for(int i=h[x]; i; i=E[i].nxt) if(!v[E[i].t]) lca_tarjan(E[i].t), fa[E[i].t]=x; //遞歸結束後再建立x與x兒子的父子關系 for(int i=p_h[x], y; i; i=P[i].nxt) //查找與x有關的所有lca詢問 if(v[y=P[i].t]){ //對於某個詢問(x, y),如果y已經訪問過了,lca(x, y)=getfa(y) P[i].lca=getfa(y); if(i%2) P[i+1].lca=P[i].lca; //P數組中pair是成對存入的,一個是(x, y), 一個是(y, x) else P[i-1].lca=P[i].lca; } } int main(){ N=read(); M=read(); S=read(); for(int i=1, x, y; i<N; i++){ x=read(); y=read(); add_edge(x, y); add_edge(y, x); } for(int i=1, a, b; i<=M; i++){ a=read(); b=read(); add_pair(a, b); add_pair(b, a); } lca_tarjan(S); for(int i=1; i<=p_tot; i++) if(i%2) printf("%d\n", P[i].lca); return 0; }
LCA(Tarjan)