文章标题

来源:互联网 发布:淘宝网的商品分类 编辑:程序博客网 时间:2024/06/05 18:05

给定一棵N 个节点的树,标号从1~N。每个点有一个权值。要求维护两种操作:

  1. C i x(0<=x<2^31) 表示将i 点权值变为x

  2. Q i j x(0<=x<2^31) 表示询问i 到j 的路径上有多少个值为x 的节点

N <= 100000

显然要用链剖, 然而直接做貌似不行,由于询问的权值只涉及到与那个权值相关的点与操作,考虑每个权值独立做,对于操作1,可以看做是在原权值上删点,新权值加点。
一个权值做完做下一个权值时,线段树可以打个clear标记表示清0 。
独立做这个想法可真是棒啊。

#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std ;#define N 200010#define psb( x )  push_back( x ) int i , j , k , Q , n , g[N] , T ; struct edge {    int y , l ; }f[N*2] ;void Ins( int x , int  y ) {    f[++T].y  = y , f[T].l = g[x] , g[x] = T ;    f[++T].y  = x , f[T].l = g[y] , g[y] = T ;}int w[N] ;struct stream {    int x , y , va ;    int id ;}z[ N * 3 ] ;char s[2] ;bool cmp( stream a , stream b ) {    return  a.va < b.va ;}bool _cmp( stream a , stream b ) {    return  a.id < b.id ;}int tmp[N*3] ;struct Operation {    int typ , x , y , ori ;    // typ : 1 delete     //   2 Insert     //   3 Query};vector< Operation > seq[ N * 3 ] ;int l[32][N] , de[N] , fa[N] , tid[N] , top[N] , siz[N] , son[N] , dfn , inx[32] ;void Find_Edge( int po ) {    int ax = 0  ;      siz[po] = 1 ;    l[0][po] = fa[po] ;    for( i=1 ; i<=30 && de[po] >= inx[i] ; i++ ) l[i][po] = l[i-1][ l[i-1][po] ] ;    for( int k = g[po] ; k ; k = f[k].l ) if( fa[po]!=f[k].y ) {        de[ f[k].y ] = de[po] + 1 ;        fa[ f[k].y ] = po ;        Find_Edge( f[k].y ) ;        if( siz[ f[k].y ] > ax ) {            ax = siz[ f[k].y ] ;            son[po] = f[k].y ;        }        siz[po] += siz[ f[k].y ] ;    }}void Mark_Edge( int po , int anc ) {    tid[po] = ++ dfn ;    top[po] = anc ;    if( son[po] != 0 ) Mark_Edge( son[po] , anc ) ;    for( int k = g[po] ; k ; k=f[k].l ) if( f[k].y != fa[po] && f[k].y != son[po] ) {        Mark_Edge( f[k].y , f[k].y ) ;    }}int LCA( int x , int y ) {    if( de[x] > de[y] ) swap( x , y ) ;    for( int sub = de[y] - de[x] , j = 0 ; sub ; sub /= 2 , j++ ) if( sub % 2 )         y = l[j][y] ;    if( y==x ) return x ;    for( int i = 1 ; i>=0 ; ) {        for( i=30 ; i>=0 ; i-- ) if( l[i][x]!=l[i][y] ) {            x = l[i][x] , y = l[i][y] ;            break ;        }    }    return fa[x] ;}int sum[N*4] ;int ans[N] ;bool clr[N*4] ;void Effect( int l , int r , int p ) {    if( clr[p] ) {        sum[p] = 0 ;         if( l!=r ) clr[p*2] = clr[p*2+1] = 1 ;    }    clr[p] = 0 ;}void Clear( int po ) {    clr[po] = 1 ;    Effect( 1 , n , po ) ;}void Insert( int l , int r , int tar , int delta , int p ) {    int m = ( l + r ) / 2 ;    Effect( l , r , p ) ;    if( l==r ) {        sum[p] += delta ;        return ;    }    if( tar <= m )  Insert( l , m , tar , delta , p*2 ) ;        else Insert( m+1 , r , tar , delta , p*2+1 )  ;    Effect( l , m , p * 2 ) , Effect( m+1 , r , p * 2 + 1 ) ;    sum[p] = sum[p*2] + sum[p*2+1] ;}int Ask( int l , int r , int _l , int _r , int p ) {    int m = ( l+r ) / 2 ;    Effect( l , r , p ) ;    if( _l==l && _r==r ) return sum[p] ;    if( _r<=m ) return Ask( l , m , _l , _r , p*2 ) ;        else if( _l>m ) return Ask( m+1 , r , _l , _r , p*2+1 ) ;            else return Ask( l , m , _l , m , p*2 ) + Ask( m+1 , r , m+1 , _r , p*2+1 ) ;}int Chain_Process( int u , int v ) {    int lca = LCA( u , v ) ;    int k = 2 , ret = 0 ;    while( k-- ) {        while( top[u]!=top[lca] ) {            ret += Ask( 1 , n , tid[ top[u] ] , tid[u] , 1 ) ;            u = fa[ top[u] ] ;        }        ret += Ask( 1 , n , tid[ lca ] , tid[u] , 1 ) ;        swap( u , v ) ;    }    ret -= Ask( 1 , n , tid[ lca ] , tid[ lca ] , 1 ) ;    return ret ;}int main() {freopen("k.in","r",stdin ) ;freopen( "k.out","w",stdout ) ;    for( i=1,inx[0] = 1  ; i<=31 ; i++ ) inx[i] = inx[i-1] *  2 ;    scanf("%d%d",&n,&Q ) ;    for( i=1 ; i<=n ; i++ ) scanf("%d",&w[i] ) ;    for( i=2 ; i<=n ; i++ ) {        int x , y ;        scanf("%d%d" , &x,&y ) ;        Ins( x ,y ) ;    }    for( i=1 ; i<=Q ; i++ ) {        scanf("%s",s ) ;        z[i].id = i ;        if( s[0] == 'Q' ) {            scanf("%d%d%d",&z[i].x , &z[i].y , &z[i].va ) ;        } else {            scanf("%d%d",&z[i].x,&z[i].va ) ;        }    }    for( i=1 ; i<=n ; i++ ) {        z[++Q].x = i , z[Q].va = w[i] ;        z[Q].id = -1 ;        z[Q].y = i ;    }    sort( z+1 , z+1+Q , cmp ) ;    int disva = 0 ;    for( i=1 ; i<=Q ; i++ ) {        if( z[i].va != z[i-1].va ) ++disva ;        tmp[i] = disva ;    }    for( i=1 ; i<=Q ; i++ ) z[i].va = tmp[i] ;    sort( z+1 , z+1+Q , _cmp ) ;    i = 1 ;     while( z[i].id == -1 ) {        Operation P ;        P.typ = 2 ;        P.x = z[i].x ;        seq[ z[i].va ].psb( P ) ;        w[ z[i].y ] = z[i].va ;        i++ ;    }    for( ; i<=Q ; i++ ) {        Operation P ;        if( z[i].y ) {            P.x = z[i].x , P.y = z[i].y , P.typ = 3 , P.ori = z[i].id ;            seq[ z[i].va ].psb( P ) ;        } else {            P.x = z[i].x , P.typ = 1 ;            seq[ w[ z[i].x ] ].psb( P ) ;            P.typ = 2 ;            w[ z[i].x ] = z[i].va ;            seq[ z[i].va ].psb( P ) ;        }    }    Find_Edge( 1 ) ;    Mark_Edge( 1,1 ) ;    memset( ans , 255 , sizeof ans ) ;    int cnt = 0 ;    for( i=1 ; i<=disva ; i++ ) {        Clear( 1 ) ;        for( vector< Operation >::iterator it = seq[i].begin() ; it != seq[i].end() ; it++ ) {            if( it->typ== 1 ) {                Insert( 1 , n , tid[ it->x ] , -1 , 1 ) ;            } else if( it->typ==2 ) {                Insert( 1 , n , tid[ it->x ] , 1 , 1 ) ;                cnt ++ ;            } else {                ans[ it->ori ] = Chain_Process( it->x , it->y ) ;            }        }    }    for( i=1 ; i<=Q ; i++ ) if( ans[i] != -1  ) printf("%d\n",ans[i] ) ;    }    // typ : 1 delete     //   2 Insert     //   3 Query
0 0