BZOJ3531 SDOI2014 旅行 树链剖分

题意:给定一棵树,维护:1、将u的种类改为c  2、将u的权值改为w  3、求u到v路径上种类为c的点的点权和  4、求u到v路径上种类为c的点的最大点权

题解:每个宗教建一颗线段树,然后随便做……考虑到如果把每一棵线段树都建完全会MLE,所以我们开动态内存。因为给出的评级都是正整数,所以如果一个区间的和为0,delete掉

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN=100000+2;
struct HASH{
    int u;
    HASH *next;
    HASH(){}
    HASH(int _u,HASH *_next):u(_u),next(_next){}
}mem[MAXN*2];
struct NODE{
    int v,f,c,son,col,mark,depth,belong;
    HASH *child;
}node[MAXN];
typedef struct TREE{
    int l,r,s,maximum;
    TREE *lchild,*rchild;
    TREE(){}
    TREE(int _l,int _r):l(_l),r(_r),lchild(0),rchild(0){}
} *ROOT;
ROOT root[MAXN];
int N,Q,cnt;
char s[6+2];

void Insert(int u,int v){ node[u].child=&(mem[cnt++]=HASH(v,node[u].child));}

void DFS1(int x,int f,int d){
    node[x].f=f,node[x].depth=d,node[x].c=1;
    for(HASH *p=node[x].child;p;p=p->next)
        if(p->u!=f){
            DFS1(p->u,x,d+1);
            node[x].c+=node[p->u].c;
            if(node[node[x].son].c<node[p->u].c) node[x].son=p->u;
        }
}

void DFS2(int x,int b){
    node[x].belong=b,node[x].mark=++cnt;
    if(!node[x].son) return;
    DFS2(node[x].son,b);
    for(HASH *p=node[x].child;p;p=p->next)
        if(p->u!=node[x].son && p->u!=node[x].f) DFS2(p->u,p->u);
}

void Pushup(ROOT &x){
    x->s=x->maximum=0;
    if(x->lchild) x->s+=x->lchild->s,x->maximum=max(x->maximum,x->lchild->maximum);
    if(x->rchild) x->s+=x->rchild->s,x->maximum=max(x->maximum,x->rchild->maximum);
}

void Update(ROOT &x,int l,int r,int p,int v){
    if(!x) x=new TREE(l,r);
    if(l==r){
        if(!v) delete x,x=0;
        else x->s=x->maximum=v;
        return;
    }

    int m=(l+r)>>1;
    if(p<=m) Update(x->lchild,l,m,p,v);
    else Update(x->rchild,m+1,r,p,v);

    Pushup(x);
    if(!x->s) delete x,x=0;
}

int Find_Sum(ROOT &x,int l,int r){
    if(!x) return 0;
    if(x->l>=l && x->r<=r) return x->s;

    int m=(x->l+x->r)>>1,ret=0;
    if(l<=m) ret+=Find_Sum(x->lchild,l,r);
    if(r>m) ret+=Find_Sum(x->rchild,l,r);

    return ret;
}

int Query_Sum(int u,int v){
    int ret=0,col=node[u].col;
    while(node[u].belong!=node[v].belong){
        if(node[node[u].belong].depth<node[node[v].belong].depth) swap(u,v);
        ret+=Find_Sum(root[col],node[node[u].belong].mark,node[u].mark);
        u=node[node[u].belong].f;
    }

    if(node[u].depth<node[v].depth) swap(u,v);
    ret+=Find_Sum(root[col],node[v].mark,node[u].mark);

    return ret;
}

int Find_Max(ROOT &x,int l,int r){
    if(!x) return -1;
    if(x->l>=l && x->r<=r) return x->maximum;

    int m=(x->l+x->r)>>1,ret=-1;
    if(l<=m) ret=max(ret,Find_Max(x->lchild,l,r));
    if(r>m) ret=max(ret,Find_Max(x->rchild,l,r));

    return ret;
}

int Query_Max(int u,int v){
    int ret=-1,col=node[u].col;
    while(node[u].belong!=node[v].belong){
        if(node[node[u].belong].depth<node[node[v].belong].depth) swap(u,v);
        ret=max(ret,Find_Max(root[col],node[node[u].belong].mark,node[u].mark));
        u=node[node[u].belong].f;
    }

    if(node[u].depth<node[v].depth) swap(u,v);
    ret=max(ret,Find_Max(root[col],node[v].mark,node[u].mark));

    return ret;
}

int main(){
    memset(node,0,sizeof(node));

    scanf("%d %d",&N,&Q);
    for(int i=1;i<=N;i++) scanf("%d %d",&node[i].v,&node[i].col);
    for(int i=1,u,v;i<N;i++){
        scanf("%d %d",&u,&v);
        Insert(u,v),Insert(v,u);
    }

    cnt=0,DFS1(1,0,0),DFS2(1,1);

    for(int i=1;i<=N;i++) Update(root[node[i].col],1,N,node[i].mark,node[i].v);

    for(int i=1,x,y,v;i<=Q;i++){
        scanf("%s %d %d",s,&x,&y);
        if(strstr(s,"CC")){
            v=Find_Sum(root[node[x].col],node[x].mark,node[x].mark);
            Update(root[node[x].col],1,N,node[x].mark,0);
            node[x].col=y;
            Update(root[node[x].col],1,N,node[x].mark,v);
        }
        if(strstr(s,"CW")) Update(root[node[x].col],1,N,node[x].mark,y);
        if(strstr(s,"QS")) printf("%d\n",Query_Sum(x,y));
        if(strstr(s,"QM")) printf("%d\n",Query_Max(x,y));
    }

    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/WDZRMPCBIT/p/6444218.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值