给定一棵N 个节点的树,标号从1~N。每个点有一个权值。要求维护两种操作:
C i x(0<=x<2^31) 表示将i 点权值变为x
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