FZU2082 树链剖分 对边操作


0 a b,表示更新第a条路的过路费为b,1 <= a <= n-1 ;

1 a b , 表示询问a到b最少要花多少过路费。


对边操作,转化为对点的操作。  x - father[x]       =>      a[]  , 因为这条边是唯一的。


const  int  maxn = 50008 ;

int  n ;
int  siz[maxn] , top[maxn] , son[maxn] ;
int  dep[maxn] , tid[maxn] , fa[maxn] , rank[maxn]  ;
int  head[maxn] , to[maxn*2] , next[maxn*2] , edge ;
int  tim ;

void  init(){
      memset(head , -1 , sizeof(head)) ;
      memset(son , -1 , sizeof(son))  ;
      tim = edge = 0 ;
}

void  addedge(int u , int v){
      to[edge] = v , next[edge] = head[u] , head[u] = edge++ ;
      to[edge] = u , next[edge] = head[v] , head[v] = edge++ ;
}

void  dfs1(int u , int father , int d){
      dep[u] = d ;
      fa[u]  = father ;
      siz[u] = 1 ;
      for(int i = head[u] ; i != -1 ; i = next[i]){
            int v = to[i] ;
            if(v != father){
                 dfs1(v , u , d+1) ;
                 siz[u] += siz[v] ;
                 if(son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v ;
            }
      }
}

void  dfs2(int u , int tp){
      top[u] = tp ;
      tid[u] = ++tim ;
      rank[tid[u]] = u ;
      if(son[u] == -1) return  ;
      dfs2(son[u] , tp) ;
      for(int i = head[u] ; i != -1 ; i = next[i]){
           int v = to[i] ;
           if(v != son[u] && v != fa[u])  dfs2(v , v) ;
      }
}

struct  Line{
      int u , v , w ;
}line[maxn] ;

LL    a[maxn]  ,  sum[maxn<<2] ;

void  up(int t){
      sum[t] = sum[t<<1] + sum[t<<1|1] ;
}

void  make(int l , int  r , int t){
      if(l == r){
            sum[t] = a[l] ; return ;
      }
      int m = (l + r) >> 1 ;
      make(l , m , t<<1) ;
      make(m+1 , r , t<<1|1) ;
      up(t) ;
}

void  update(int l , int r , int t , int x , LL c){
      if(l == r){
             sum[t] = c ; return ;
      }
      int m = (l + r) >> 1 ;
      if(x <= m) update(l , m , t<<1 , x , c) ;
      else       update(m+1 , r , t<<1|1 , x , c) ;
      up(t) ;
}

LL   ask(int L , int R , int l , int r , int t){
     if(L <= l && r <= R)  return sum[t] ;
     int m = (l + r) >> 1 ;
     LL  s = 0 ;
     if(L <= m)  s += ask(L , R , l , m , t<<1) ;
     if(R > m)   s += ask(L , R , m+1 , r , t<<1|1) ;
     return s ;
}

LL   change(int x , int  y){
     LL t = 0 ;
     while(top[x] != top[y]){
          if(dep[top[x]] < dep[top[y]]) swap(x , y) ;
          t += ask(tid[top[x]] , tid[x] , 1 , n , 1)  ;
          x = fa[top[x]] ;
     }
     if(x == y) return t ;
     if(dep[x] > dep[y])  swap(x , y) ;
     t += ask(tid[x] + 1 , tid[y] , 1 , n , 1) ; // 注意是  tid[x] + 1
     return t ;
}

int  main(){
     int  m  , i , k , l , r  ;
     memset(a , 0 , sizeof(a)) ;

     while(scanf("%d%d" ,&n , &m) != EOF){

          init()  ;
          for(i = 1 ; i < n ; i++){
               scanf("%d%d%d" ,&line[i].u , &line[i].v , &line[i].w) ;
               addedge(line[i].u , line[i].v) ;
          }

          dfs1(1 , 0 , 0) ;
          dfs2(1 , 1) ;

          for(i = 1 ; i < n ; i++){
                if(tid[line[i].u] < tid[line[i].v])
                     swap(line[i].u , line[i].v) ;
                a[tid[line[i].u]] = LL(line[i].w) ;
          }

          make(1 , n , 1) ;

          while(m--){
               scanf("%d%d%d" , &k , &l , &r) ;
               if(k == 0)  update(1 , n , 1 , tid[line[l].u] , LL(r)) ;
               else        printf("%I64d\n" , change(l , r)) ;
          }

     }
     return  0 ;
}


你可能感兴趣的:(FZU2082 树链剖分 对边操作)