LCA的 Trajan 算法
阿新 • • 發佈:2018-10-02
鄰接 sizeof n) out 遞歸遍歷 blank 父節點 ace article
參考博客
參考博客
根據博客的模擬,就可以知道做法和思想。
現在就是實現他。
例題 :hdu 2586
題意:m 個詢問,x 到 y 的距離,我們的思想就是求出:x到根的距離+y到根的距離-2*(lca[ x ,y ])到跟的距離。
代碼:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; const int max_edge=100005;//邊數 const int max_Q=405;//問題 constint max_=40005;//節點 struct Tree{//樹-鄰接表 int to; int v; int next; }; struct Question{//離線-問題 int to; int id; int next; }; struct Tree a[max_edge];//樹數組 struct Question b[max_];//問題數組 int N,M; int edge[max_];//邊記錄next int tot1,tot2; bool vis[max_];//標記數組 int st[max_Q],ed[max_Q];//問題的x和y int question[max_];//問題-記錄next int fa[max_];//父節點 int dis[max_];//到根的距離 int LCA[max_Q];//問題的LCA void add_edge(int x,int y,int v)//建樹 { a[++tot1].to=y; a[tot1].v=v; a[tot1].next=edge[x]; edge[x]=tot1; } void add_question(int x,int y,int id)//離線 { b[++tot2].to=y; b[tot2].id=id; b[tot2].next=question[x]; question[x]=tot2; } int find_fa(int x)//尋找父節點 { if(fa[x]==x) return x; return fa[x]=find_fa(fa[x]); } void Tarjan(int x) { fa[x]=x;//作為當前的根節點,將其父親指向自己 vis[x]=1;//標記 for(int i=question[x];i;i=b[i].next)//尋找問題中與自己有關節點 { int go_to=b[i].to; if(vis[go_to]==true)//如果有關節點走過,記錄LCA LCA[b[i].id]=find_fa(go_to); } for(int i=edge[x];i;i=a[i].next)//沿邊遍歷 { int go_to=a[i].to; if(vis[go_to]==false) { dis[go_to]=dis[x]+a[i].v;//更新距離 Tarjan(go_to);//遞歸遍歷 fa[go_to]=x;//歸並父節點 } } } int main() { int T; cin>>T;//測試組數 while(T--) { memset(vis,0,sizeof(vis)); memset(question,0,sizeof(question)); memset(edge,0,sizeof(edge)); memset(dis,0,sizeof(dis)); memset(LCA,0,sizeof(LCA)); tot1=0,tot2=0;//初始歸零 cin>>N>>M; for(int i=0;i<N-1;i++) { int x,y,v; cin>>x>>y>>v; add_edge(x,y,v);//雙向建邊 add_edge(y,x,v); } for(int i=0;i<M;i++) { int x,y; cin>>x>>y; add_question(x,y,i); add_question(y,x,i);//保證找有關點時不漏 st[i]=x,ed[i]=y;//記錄問題的x,y } Tarjan(1); for(int i=0;i<M;i++) { int temp=dis[st[i]]+dis[ed[i]]-(2*dis[LCA[i]]);//結果 cout<<temp<<endl; } } }
LCA的 Trajan 算法