【Bzoj3531】旅行

24 篇文章 0 订阅
14 篇文章 0 订阅

题意:有n个城市,每个城市有权值和颜色,支持的操作有单点修改权值,单点修改颜色,查询区间同颜色之和,查询区间同颜色最大值。


思路:对于每种颜色,放入不同的线段树,但其实整个加起来还是还是n个结点,值得注意的是,这里要使用动态开点,要一步步记录左右儿子的编号,而不能使用2i,2i+1直接去找,而这样建树的话,就可以很方便的查询同颜色的结点了,修改操作啥的把原颜色中的结点改为0,再在现在的颜色中开点就可以了。


#include <cstdio>
#include <algorithm>

#define Rep(i,s,t) for(int i=s;i<=t;i++)
#define For(i,s,t) for(int i=s;i;i=t)

using namespace std;

const int maxx = 100000 + 25;
const int maxm = 4000000 + 25;
const int Inf = (unsigned)(-1) >> 1;

int head[maxx],nxt[maxx<<1],to[maxx<<1],a[maxx],c[maxx];
int top[maxx],rnk[maxx],size[maxx],dpt[maxx],ftr[maxx],son[maxx];
int T[maxm],Tmax[maxm],lc[maxm],rc[maxm],rt[maxx];

int num,cnt,tot,n,m,x,y,k;
char f[8];

namespace Y{

    void Ins(int x,int y) {to[++num]=y;nxt[num]=head[x];head[x]=num;}    
    
    void Dfs1(int x){
        size[x] = 1;
        For( i , head[x] , nxt[i] ){
            int now = to[i];if(now == ftr[x]) continue;
            dpt[now] = dpt[x] + 1;ftr[now] = x;
            Dfs1(now);size[x] += size[now];
            if(size[now] > size[son[x]]) son[x] = now;
        }
    }
    
    void Dfs2(int x,int brn){
        rnk[x] = ++cnt;top[x] = brn;
        if(son[x]) Dfs2(son[x],brn);
        For( i , head[x] , nxt[i] )
            if(to[i] != ftr[x] && to[i] != son[x])
                Dfs2(to[i],to[i]);
    }
    
    void upt(int i){
        T[i] = T[lc[i]] + T[rc[i]];
        Tmax[i] = max(Tmax[lc[i]],Tmax[rc[i]]);
    }
    
    void modify(int &i,int pos,int l,int r,int k){
        if(!i) i = ++tot;if(l == r) {T[i] = Tmax[i] = k;return;}
        int mid = (l+r) >> 1;
        if(pos <= mid) modify(lc[i],pos,l,mid,k);
        if(pos >  mid) modify(rc[i],pos,mid+1,r,k);
        upt(i);
    }
    
    void chk(int &tmp,int pls,int flag){
        if(flag == 0) tmp = tmp + pls;
        if(flag == 1) tmp = max(tmp,pls);
    }
    
    int Query(int i,int x,int y,int l,int r,int flag){
        if(x <= l && r <= y) return flag? Tmax[i] : T[i];
        int ans = (flag)? -Inf : 0;int mid = (l+r) >> 1;
        if(x <= mid) chk(ans,Query(lc[i],x,y,l,mid,flag),flag);
        if(y >  mid) chk(ans,Query(rc[i],x,y,mid+1,r,flag),flag);
        return ans;
    }
    
    int Get(int i,int x,int y,int flag){
        int ans = (flag)? -Inf : 0;
        while(top[x] != top[y]){
            if(dpt[top[x]] > dpt[top[y]]) x^=y^=x^=y;
            chk(ans,Query(i,rnk[top[y]],rnk[y],1,n,flag),flag);
            y = ftr[top[y]];
        }
        if(rnk[x] > rnk[y]) x^=y^=x^=y;
        chk(ans,Query(i,rnk[x],rnk[y],1,n,flag),flag);
        return ans;
    }
    
}

using namespace Y;

int main(){
    scanf("%d%d",&n,&m);
    Rep( i , 1 , n ) scanf("%d%d",&a[i],&c[i]);
    Rep( i , 1 , n-1 ) scanf("%d%d",&x,&y),Ins(x,y),Ins(y,x);
    Dfs1(1),Dfs2(1,1);Rep( i , 1 , n ) modify(rt[c[i]],rnk[i],1,n,a[i]);
    while( m-- ){
        scanf("%s",f);
        if(f[1] == 'S') scanf("%d%d",&x,&y),printf("%d\n",Get(rt[c[x]],x,y,0));
        if(f[1] == 'C'){ 
            scanf("%d%d",&x,&y);
            modify(rt[c[x]],rnk[x],1,n,0);
            c[x]=y;
            modify(rt[c[x]],rnk[x],1,n,a[x]);
        }
        if(f[1] == 'W')
            scanf("%d%d",&x,&y),a[x]=y,modify(rt[c[x]],rnk[x],1,n,a[x]);
        if(f[1] == 'M') scanf("%d%d",&x,&y),printf("%d\n",Get(rt[c[x]],x,y,1));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值