pku2763 Housewife Wind

题意:给定一棵有n( n < 100001 )个结点的带边权的树,处理以下一共q(q < 100001)个操作:

1,改变树的一条边的权;

2,求给定点和某点的距离,后者是编号为1的结点,若是第一次执行操作2,否则为上次执行操作2的给定点。

没有了操作1,这题就是典型的LCA,于是怎样有效地执行操作1就是这题的关键。还记得LCA到RMQ的转化吗点我,过程中DFS会生成一条回路,并且产生一个从遍历次序到结点编号的满射,我们称它为order[]。我们知道,若以结点到根的距离作为树的深度,如果一条边的权增加了delta,那么这条边链接的子树内的所有结点的深度都增加了delta。又因为子树内的结点的遍历次序是连续的,所以我们可以建立从 遍历次序 到 到根的距离的映射dist[],于是每次执行操作1只需对dist[]的一片连续区域作修改即可,可以用线段树或者树状数组。

搞定了操作1,我们发现操作2也被搞出来了,因为LCA(u,v)=order[RMQ(dist[出现u的任意遍历序号...出现v的任意遍历序号])],可能这是出题者的意图吧。

 

 

#include  < iostream >
#include 
< vector >
#include 
< cmath >
using   namespace  std;

#define  MAXN 200005
#define  LOG 20
typedef pair
< int , int >  PAIR;


int  order[MAXN],ecnt,dist[MAXN],first[MAXN],last[MAXN],n,q,st,p[MAXN],maxorder,c[MAXN],mn[MAXN][LOG],b[MAXN];
// first[u]表示u首次出现的遍历序号,last[u]表示u最后出现的遍历序号
bool  visited[MAXN];

struct  Edge{
    
int  v,weight,next;
}edg[MAXN];


void  init(){
    ecnt
= 0 ;
    memset(p,
- 1 , sizeof (p));
    memset(dist,
0 , sizeof (dist));
    maxorder
= 1 ;
    memset(visited,
false , sizeof (visited));
    memset(c,
0 , sizeof (c));
}


void  dfs( int  pre, int  u, int  w){
    
int  i,v,ordertmp;
    
    visited[u]
= true ;
    last[u]
= first[u] = maxorder;
    order[maxorder]
= u;
    dist[maxorder]
= dist[last[pre]] + w;
    ordertmp
= maxorder ++ ;

    
for (i = p[u];i !=- 1 ;i = edg[i].next){
        v
= edg[i].v;
        
if ( ! visited[v]){
            
            dfs(u,v,edg[i].weight);
            order[maxorder]
= u;
            last[u]
= maxorder;
            dist[maxorder]
= dist[ordertmp];
            maxorder
++ ;
        }
    }
}

//////////////////////////////////////////////////////////////////////// //
// 树状数组
inline  int  lowbit( int  x){
    
return  x & ( - x);
}


int  down( int  x){
    
int  i,res = 0 ;
    
for (i = x;i > 0 ;i -= lowbit(i))
        res
+= c[i];
    
return  res;
}

void  up( int  x, int  t){
    
int  i;
    
for (i = x;i < maxorder;i += lowbit(i))
        c[i]
+= t;
}

void  build(){
    
int  i;
    
for (i = 1 ;i < maxorder;i ++ )
        b[i]
= dist[i] - dist[i - 1 ];
    
for (i = 1 ;i < maxorder;i ++ ){
        up(i,b[i]);
    }
}

//////////////////////////////////////////////////////////////////////// //
// spares table
void  preprocess(){
    
int  i,j;
    
for (i = 1 ;i < maxorder;i ++ )
        mn[i][
0 ] = i;
    
for (j = 1 ;( 1 << j) <= maxorder;j ++ ){
        
for (i = 1 ;i + ( 1 << j) - 1 < maxorder;i ++ ){
            
if (dist[mn[i][j - 1 ]] <= dist[mn[i + ( 1 << (j - 1 ))][j - 1 ]])
                mn[i][j]
= mn[i][j - 1 ];
            
else
                mn[i][j]
= mn[i + ( 1 << (j - 1 ))][j - 1 ];

        }
    }
}

int  RMQ( int  i, int  j){
    
if (i > j){
        
int  t = i;
        i
= j;
        j
= t;
    }
    
int  k = log(( double )j - i + 1 ) / log(( double ) 2 );
    
if (dist[mn[i][k]] <= dist[mn[j - ( 1 << k) + 1 ][k]])
        
return  mn[i][k];
    
else
        
return  mn[j - ( 1 << k) + 1 ][k];
}

//////////////////////////////////////////////////////////////////////// //
// main
int  main(){
    
int  i,j,u,v,weight,flag,w;
    init();
    vector
< PAIR >  vec;
    scanf(
" %d%d%d " , & n, & q, & st);
    
for (i = 0 ;i < n - 1 ;i ++ ){
        scanf(
" %d%d%d " , & u, & v, & weight);
        vec.push_back(make_pair(u,v));
        edg[ecnt].next
= p[u];
        edg[ecnt].v
= v;
        edg[ecnt].weight
= weight;
        p[u]
= ecnt ++ ;
        edg[ecnt].next
= p[v];
        edg[ecnt].v
= u;
        edg[ecnt].weight
= weight;
        p[v]
= ecnt ++ ;
    }

    dfs(
1 , 1 , 0 );

//      for(i=1;i<maxorder;i++)
//          printf("%d ",order[i]);
//      printf("\n");
//      for(i=1;i<maxorder;i++)
//          printf("%d ",dist[i]);
//      printf("\n");
//      for(i=1;i<=n;i++)
//          printf("%d ",first[i]);
//      printf("\n");
//      for(i=1;i<=n;i++)
//          printf("%d ",last[i]);
//      printf("\n");

    build();
    preprocess();

    
for (i = 0 ;i < q;i ++ ){
        scanf(
" %d " , & flag);
        
if (flag){
            scanf(
" %d%d " , & j, & weight);
            j
-- ;
            u
= vec[j].first;
            v
= vec[j].second;
            
if (dist[first[u]] > dist[first[v]]){
                
int  t = u;
                u
= v;
                v
= t;
            }
            w
= down(first[v]) - down(first[u]);
            up(first[v],weight
- w);
            
if (last[v] + 1 < maxorder)
                up(last[v]
+ 1 ,w - weight);
        }
        
else {
            scanf(
" %d " , & u);
            v
= order[RMQ(first[u],first[st])];
            printf(
" %d\n " ,down(first[u]) + down(first[st]) - 2 * down(first[v]));
            st
= u;
        }
    }
    
return   0 ;
}
            

 

 

你可能感兴趣的:(pku)