BZOJ3531 【Sdoi2014】旅行

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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值