LCA演算法模板
阿新 • • 發佈:2018-12-11
#include<string> #include<cstring> #include<iostream> #include<cstdio> #define LL long long using namespace std ; /* LAC演算法模板 題目: POJ - how far way ? 複雜度(n + k ) k 次詢問 雙鏈式前向星 (一個建圖 一個回答) */ int n , m ; const int maxn = 100500; int head[maxn] ; // 鏈式前向星 int dis[maxn] ; // 用於記錄路徑之和(用法; 有頭節點一直往下累加 , dis[v] 表示從節點1到v的距離) int pre[maxn] ; // 並查集函式 int LAC[maxn] ; // 用於記錄公共祖先是誰 int _head[maxn] ; int ans[maxn] , ans1[maxn] ; int vis[maxn] ; // vis標記 ,因為是雙向邊,不加vis標記會造成死迴圈 int par[maxn] ; struct edge{ int to , next ; int w ; }edge[maxn ]; struct node{ int to , next , num ; }st[maxn]; int cnt = 0 , tot = 0; int find(int x) { int r=x; while(pre[r]!=r) r=pre[r];//找到他的前導結點 return r; } void init(){ cnt = 0 ; tot = 0 ; memset(head , -1 , sizeof(head)) ; //memset(dis , 0 , sizeof(dis)) ; // memset(vis , 0 , sizeof(vis)) ; memset(_head , -1 , sizeof(_head)) ; // memset(LAC , -1 , sizeof(LAC) ) ; //memset(ans , 0 , sizeof(ans)) ; //memset(ans1 , 0 , sizeof(ans1)) ; for(int i = 1 ; i <= n ; i++){ par[i] = pre[i] = i ; vis[i] = 0 ; LAC[i] = -1 ; dis[i] = 0 ; } } void add(int u , int v , int w){ edge[++cnt].to = v ; edge[cnt].w = w ; edge[cnt].next = head[u] ; head[u] = cnt ; } void add_pro(int u , int v , int num ) { st[++tot].to = v ; st[tot].num = num ; st[tot].next = _head[u] ; _head[u] = tot ; } void tarjin(int u){ vis[u] = 1 ; pre[u] = u ; // for(int i = head[u] ; i != -1 ; i = edge[i].next ){ int v = edge[i].to ; if(!vis[v]){ dis[v] = edge[i].w + dis[u] ; // 求出1節點到 v節點的距離 (就是這裡沒注意順序WA了好多次。。。) tarjin(v) ; pre[v] = u ; // Union函式 因為是樹就不需要判斷了 } } for(int i = _head[u] ; i != -1 ; i = st[i].next){ int v = st[i].to ; if(vis[v]){ LAC[st[i].num] = find(v) ; } } } int main(){ int q; while(scanf("%d %d %d",&n,&m,&q ) != EOF){ init() ; int u , v ; int w ; for(int i = 0 ; i <m ; i++){ scanf("%d %d %d",&u,&v,&w) ; add(u , v, w ) ; add(v , u, w ) ; } for(int i = 0 ; i < q ; i++){ scanf("%d %d",&u,&v) ; add_pro(u , v, i) ; add_pro(v , u, i) ; ans[i] = u , ans1[i] = v ; // 這個用於記錄問題的答案, 因為add_pro這個函式相當於構圖 } // cout << kk[0] << endl ; for(int i = 1 ; i <= n ; i++){ if(vis[i] == 0 ) {memset(vis , 0, sizeof(vis)) ; tarjin(i) ;} } for(int i = 0 ; i < q ; i++){ if(LAC[i] == -1) cout << "Not connected" <<endl ; else printf("%d\n",dis[ans[i]] + dis[ans1[i]] - 2 * dis[LAC[i]]) ; // 有dis陣列的意義來理解 } } return 0 ; }