Tarjan之求LCA
阿新 • • 發佈:2017-09-06
算法 get ios nbsp read 而在 hid 統一 turn
Tarjan之求LCA
不要問我為什麽寫完Tarjan還要再補一句“求LCA的那個”
因為只說Tarjan的話完全不知道你指的是哪個算法……
勞模Tarjan同誌證明了好多算法,而且全都叫Tarjan算法(是不會起名了嗎x)
這個Tarjan是一個求LCA的離線算法
關於什麽是在線什麽是離線……
“所謂的在線算法就是實時性的,比方說,給你一個輸入,算法就給出一個輸出,就像是http請求,請求網頁
一樣。給一個實時的請求,就返回給你一個請求的網頁。而離線算法則是要求一次性讀入所有的請求,然後在
統一處理。而在處理的過程中不一定是按照請求的輸入順序來處理的。說不定後輸入的請求在算法的執行過程
中是被先處理的。”
↑從網上抄來的w↑感覺很好懂……
因為是離線做法,重新排列了一下解決詢問的順序,所以要比在線算法快
Tarjan的前置技能是dfs和並查集,不會的趕緊去學x
那麽正片開始!
因為這是個離線算法,所以讀進來各條邊之後繼續讀進來所有詢問並存起來
然後從根開始dfs
訪問到每個點的時候,先遍歷從這個點u出去的所有邊,dfs未訪問過的點v,訪問後把這個點並到u的並查集上
然後掃一遍和u有關的所有詢問及其涉及到的點v
如果點v已經被訪問過了,那麽說明u和v的LCA已經算好了
真相只有一個,LCA就是點v所在的並查集的祖先
趕緊存進答案數組裏……
全部dfs完成後,答案也全部算完了,按詢問序輸出答案就OK了
具體實現可以看代碼OvO
//Tarjan lca #include<iostream> #include<cstdio> using namespace std; const int N=500009; int n,m,s,cnt,tot,ep[N],qp[N],fa[N]; bool vis[N]; struct edge{ int to,nex; }e[N<<1]; struct query{ int to,nex,ans; }q[N<<1]; int read() { int an=0; charTarjan LCA(wypx)ch=getchar(); while(!(‘0‘<=ch&&ch<=‘9‘))ch=getchar(); while(‘0‘<=ch&&ch<=‘9‘){an=an*10+ch-‘0‘;ch=getchar();} return an; } int found(int x) { if(x==fa[x])return x; return fa[x]=found(fa[x]); } void adde(int u,int v) { ++cnt; e[cnt].to=v; e[cnt].nex=ep[u]; ep[u]=cnt; } void addq(int u,int v) { ++tot; q[tot].to=v; q[tot].nex=qp[u]; qp[u]=tot; } void dfs(int u) { vis[u]=1;fa[u]=u; for(int i=ep[u];i;i=e[i].nex) { int v=e[i].to; if(!vis[v]){dfs(v);fa[v]=u;} } for(int i=qp[u];i;i=q[i].nex) { int v=q[i].to; if(vis[v]) { q[i].ans=found(v); if(i&1)q[i+1].ans=q[i].ans; else q[i-1].ans=q[i].ans; } } } int main() { n=read(),m=read(),s=read(); for(int i=1;i<n;++i) { int x=read(),y=read(); adde(x,y);adde(y,x); } for(int i=1;i<=m;++i) { int x=read(),y=read(); addq(x,y);addq(y,x); } dfs(s); for(int i=1;i<=m;++i) printf("%d\n",q[i<<1].ans); return 0; }
偷著放一份s菌的代碼
#include<iostream> #include<cstdio> #include<cstdlib> #include<queue> #include<algorithm> using namespace std; int read(){ int an=0,f=1;char ch=getchar(); while(!(‘0‘<=ch&&ch<=‘9‘)){if(ch==‘-‘)f=-f;ch=getchar();} while(‘0‘<=ch&&ch<=‘9‘){an=an*10+ch-‘0‘;ch=getchar();} return an*f; } int n,m,s,cnt,qf[500099],f[500099],fa[500099],ans[500099<<1]; int x,y; bool vis[500099]; int found(int x){ if(fa[x]!=x)fa[x]=found(fa[x]); return fa[x];} struct saber{ int to,nex; }b[500099<<1]; struct question{ int to,nex; }qu[500099<<1]; void add(int x,int y){ cnt++;b[cnt].to=y; b[cnt].nex=f[x];f[x]=cnt; } void add(int x,int y,int z){ qu[z].to=y; qu[z].nex=qf[x]; qf[x]=z; } void dfs(int x){ fa[x]=x;vis[x]=1;//cout<<x<<" "; for(int i=f[x];i;i=b[i].nex){ int v=b[i].to; if(!vis[v]){ dfs(v); fa[v]=x; } } for(int i=qf[x];i;i=qu[i].nex){ int v=qu[i].to; if(vis[v]){ ans[i]=found(v); if(i&1)ans[i+1]=ans[i]; else ans[i-1]=ans[i]; } } } int main(){ n=read();m=read();s=read(); for(int i=1;i<n;i++){ int x,y;x=read();y=read(); add(x,y);add(y,x); } for(int i=1;i<=m;i++){ x=read();y=read(); add(x,y,i*2-1);add(y,x,i*2); } dfs(s); for(int i=1;i<=m;i++){ cout<<ans[2*i]<<endl;} return 0; }Tarjan LCA (s_a_b_e_r)
by:wypx
Tarjan之求LCA