poj 2763树链剖分

const int maxn = 100008 ;

int  to[maxn*2] , next[maxn*2] , head[maxn*2] , edge ;

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

int  dep[maxn] , tid[maxn] , fa[maxn] , rnk[maxn] , son[maxn]  , siz[maxn] , top[maxn] ;

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

int  dfntime ;
void dfs2(int u , int tp){
     top[u] = tp ;
     tid[u] = ++dfntime ;
     rnk[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) ;
     }
}

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

struct  E{
        int u , v , w ;
}e[maxn] ;

int  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 , int 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) ;
}

int  ask(int L , int R , int l , int r , int t){
     if(L <= l && r <= R) return sum[t] ;
     int m = (l + r) >> 1 ;
     int 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 ;
}

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

int  main(){
     int   q , s ;
     while(scanf("%d%d%d" , &n ,&q ,&s) != EOF){
          _init() ;
          for(int i = 1 ; i < n ; i++){
               scanf("%d%d%d" ,&e[i].u ,&e[i].v ,&e[i].w) ;
               addedge(e[i].u , e[i].v) ;
          }

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

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

          make(1 , n , 1) ;

          int kd  , i , v , w ;
          while(q--){
               scanf("%d" , &kd) ;
               if(kd == 0){
                   scanf("%d" , &v) ;
                   printf("%d\n" , change(s , v)) ;
                   s = v ;
               }
               else{
                   scanf("%d%d" , &i , &w) ;
                   update(1 , n , 1 , tid[e[i].u] , w) ;
               }
          }
     }

     return 0 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值