1. 程式人生 > >LCA演算法模板

LCA演算法模板

#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 ;
}