Description
给定一棵有n个节点的无根树,每个节点有w和c两个属性,有四种操作:
1、更改某个节点的c属性
2、更改某个节点的w属性
3、询问x到y的路径上c属性和x相同的节点的w属性之和
4、询问x到y的路径上c属性和x相同的节点的w属性最大值
Solution
询问主要和w有关,而c又只有单点修改,于是我们可以为每一个c的值建一棵线段树,与当前线段数所代表的c值不同的节点在当前线段树上的值为0,每次查询x节点的c值所对应的线段数即可。
为了防止MLE这题要用动态开点的方式建线段树。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn = 100005;
const int INF = 0x3f3f3f3f;
#define LL long long
struct edge{
int x,y,next;
edge(){}
edge(int _x,int _y,int _nt):x(_x),y(_y),next(_nt){}
}e[maxn << 1];
int head[maxn],tot=0;
int top[maxn],siz[maxn],son[maxn],fa[maxn],p[maxn],dep[maxn];
int n,T,Q;
inline void addedge(int x,int y){
e[++tot] = edge( x , y , head[x] ); head[x] = tot;
e[++tot] = edge( y , x , head[y] ); head[y] = tot;
}
void DFS1(int x){
siz[x] = 1; son[x] = 0;
for(int y,i = head[x] ; i ; i = e[i].next ){
y = e[i].y;
if( dep[y] ) continue;
dep[y] = dep[x] + 1;
fa[y] = x;
DFS1( y );
siz[x] += siz[y];
if( siz[y] > siz[son[x]] ) son[x] = y;
}
}
void DFS2(int x,int chain){
p[x] = ++T; top[x] = chain;
if( son[x] ) DFS2( son[x] , chain );
for(int y,i = head[x] ; i ; i = e[i].next ){
y = e[i].y;
if( p[y] || son[x] == y )continue;
DFS2( y , y );
}
}
struct node{
int mx;
LL sum;
node *L,*R;
}mempool[1200005];
int cnt=0;
node* root[maxn];
node* new_node(int _mx,LL _sum){
node* t = &mempool[++cnt];
t->mx = _mx;
t->sum = _sum;
t->L = t->R = NULL;
return t;
}
int mx(node* t){return t == NULL ? -INF : t->mx;}
LL sum(node* t){return t == NULL ? 0 : t->sum;}
void pushup(node* t){
t->mx = max ( mx(t->L) , mx(t->R) );
t->sum = sum(t->L) + sum(t->R);
}
void change(node* &t,int L,int R,int pos,int d){
if( t == NULL ) t = new_node(0,0);
if( L == R ){
t->mx = t->sum = d;
return;
}
int mid = ( L + R ) >> 1;
if(pos <= mid) change( t->L , L , mid , pos , d );
else change( t->R , mid+1 , R , pos , d );
pushup(t);
}
LL query_sum(node* t,int L,int R,int qL,int qR){
if( t == NULL ) return 0;
if( L == qL && qR == R) return t->sum;
int mid = ( L + R ) >> 1;
if( qR <= mid ) return query_sum( t->L , L , mid , qL , qR );
if( mid < qL ) return query_sum( t->R , mid+1 , R , qL ,qR );
return query_sum( t->L , L , mid , qL , mid ) + query_sum( t->R , mid+1 , R , mid+1 , qR );
}
int query_mx(node *t,int L,int R,int qL,int qR){
if( t == NULL ) return 0;
if( L == qL && qR == R ) return t->mx;
int mid = ( L + R ) >> 1;
if( qR <= mid ) return query_mx( t->L , L , mid , qL , qR );
if( mid < qL ) return query_mx( t->R , mid+1 , R , qL , qR );
return max( query_mx( t->L , L , mid , qL , mid ) , query_mx( t->R , mid+1 , R , mid+1 , qR ) );
}
void solve_sum(node* t,int x,int y){
LL ans = 0;
while( top[x] != top[y] ){
if( dep[top[x]] < dep[top[y]] ) swap( x , y );
ans += query_sum( t , 1 , n , p[top[x]] , p[x] );
x = fa[top[x]];
}
if( dep[x] > dep[y] ) swap( x , y );
ans += query_sum( t , 1 , n , p[x] , p[y] );
printf("%lld\n",ans);
}
void solve_mx(node* t,int x,int y){
int ans = 0;
while( top[x] != top[y] ){
if( dep[top[x]] < dep[top[y]] )swap( x , y );
ans = max( ans , query_mx( t , 1 , n ,p[top[x]] , p[x] ) );
x = fa[top[x]];
}
if( dep[x] > dep[y] ) swap( x , y );
ans = max( ans , query_mx( t , 1 , n , p[x] , p[y] ) );
printf("%d\n",ans);
}
int w[maxn],c[maxn];
int main(){
scanf("%d%d",&n,&Q);
for(int i = 1 ; i <= n ; i++ ){
scanf("%d%d",&w[i],&c[i]);
}
for(int x,y,i = 1 ; i <= n-1 ; i++ ){
scanf("%d%d",&x,&y);
addedge(x,y);
}
dep[1] = 1;
DFS1( 1 );
DFS2( 1 , 1 );
for(int i = 1 ; i <= n ; i++)
change( root[c[i]] , 1 , n , p[i] , w[i] );
char str[5];int x,y;
for(int i = 1 ; i <= Q ; i++ ){
scanf("%s%d%d",str,&x,&y);
if(str[1] == 'C'){
change( root[c[x]] , 1 , n , p[x] , 0 );
change( root[y] , 1 , n , p[x] , w[x]);
c[x] = y;
}
if(str[1] == 'W'){
change( root[c[x]] , 1 , n , p[x] , y );
w[x] = y;
}
if(str[1] == 'S')
solve_sum(root[c[x]],x,y);
if(str[1] == 'M')
solve_mx(root[c[x]],x,y);
}
}