bzoj 3531: [Sdoi2014]旅行

14 篇文章 0 订阅
3 篇文章 0 订阅

题意:一棵树上,每个点有颜色和权值,多个更改和询问,求某种颜色在一条路径上的最大值或和。
题解:树剖,每种颜色开一个线段树,动态开点就好了。
代码:

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

int n,q,fst[100010],num=0,w[100010],c[100010],en=0;
struct edge
{
    int x,y,n;
}e[200010];
struct tree
{
    int cs,cm;
    tree *lc,*rc;
    tree()
    {
        cs=cm=0;
        lc=rc=NULL;
    }
}*root[100010];
struct pnt
{
    int f,s,sz,tp,dp,en;
}p[100010];

void ins(int x,int y)
{
    e[++num]={x,y,fst[x]};
    fst[x]=num;
}
void dfs1(int x,int f)
{
    p[x].f=f;
    p[x].sz=1;
    p[x].dp=p[f].dp+1;
    p[x].s=0;
    for(int i=fst[x];i;i=e[i].n)
    {
        int y=e[i].y;
        if(y==f)
        continue;
        dfs1(y,x);
        if(p[y].sz>p[p[x].s].sz)
        p[x].s=y;
        p[x].sz+=p[y].sz;
    }
}
void dfs2(int x,int tp)
{
    p[x].en=++en;
    p[x].tp=tp;
    if(p[x].s)
    {
        dfs2(p[x].s,tp);
        for(int i=fst[x];i;i=e[i].n)
        {
            int y=e[i].y;
            if(y==p[x].f||y==p[x].s)
            continue;
            dfs2(y,y);
        }
    }
}
void pushup(tree* x)
{
//  printf("0x%x 0x%x 0x%x",x,x->lc,x->rc);
    x->cm=x->cs=0;
    if(x->lc!=NULL)
    {
        x->cm=max(x->cm,x->lc->cm);
        x->cs+=x->lc->cs;
    }
    if(x->rc!=NULL)
    {
        x->cm=max(x->cm,x->rc->cm);
        x->cs+=x->rc->cs;
    }
}
tree* chg(tree* rt,int l,int r,int x,int p)
{
    if(rt==NULL)
    rt=new tree;
//  printf("0x%x %d %d %d %d\n",rt,l,r,x,p);
    if(l==r)
    {
        rt->cs=rt->cm=x;
        return rt;
    }
    int md=l+r>>1;
    if(p<=md)
    rt->lc=chg(rt->lc,l,md,x,p);
    else
    rt->rc=chg(rt->rc,md+1,r,x,p);
    pushup(rt);
    return rt;
}
tree* del(tree* rt,int l,int r,int p)
{
    if(rt==NULL)
    return NULL;
    if(l==r)
    {
        delete rt;
        return NULL;
    }
    int md=l+r>>1;
    if(p<=md)
    rt->lc=del(rt->lc,l,md,p);
    else
    rt->rc=del(rt->rc,md+1,r,p);
    if(rt->lc==NULL&&rt->rc==NULL)
    {
        delete rt;
        return NULL;
    }
    pushup(rt);
    return rt;
}
int get1(tree* rt,int l,int r,int ll,int rr)
{
    if(rt==NULL)
    return 0;
    if(l==ll&&r==rr)
    {
        return rt->cs;
    }
    int md=l+r>>1;
    if(rr<=md)
    return get1(rt->lc,l,md,ll,rr);
    else if(ll>md)
    return get1(rt->rc,md+1,r,ll,rr);
    else
    {
        return get1(rt->lc,l,md,ll,md)+get1(rt->rc,md+1,r,md+1,rr);
    }
}
int get2(tree* rt,int l,int r,int ll,int rr)
{
    if(rt==NULL)
    return 0;
    if(l==ll&&r==rr)
    {
        return rt->cm;
    }
    int md=l+r>>1;
    if(rr<=md)
    return get2(rt->lc,l,md,ll,rr);
    else if(ll>md)
    return get2(rt->rc,md+1,r,ll,rr);
    else
    {
        return max(get2(rt->lc,l,md,ll,md),get2(rt->rc,md+1,r,md+1,rr));
    }
}
int slv1(tree* rt,int x,int y)
{
    int ans=0;
    while(p[x].tp!=p[y].tp)
    {
        if(p[p[x].tp].dp<p[p[y].tp].dp)
        swap(x,y);
        int tx=p[x].tp,y=p[y].tp;
        ans+=get1(rt,1,en,p[tx].en,p[x].en);
        x=p[tx].f;
    }
    if(p[x].dp>p[y].dp)
    swap(x,y);
    ans+=get1(rt,1,en,p[x].en,p[y].en);
    return ans;
}
int slv2(tree* rt,int x,int y)
{
    int ans=0;
    while(p[x].tp!=p[y].tp)
    {
        if(p[p[x].tp].dp<p[p[y].tp].dp)
        swap(x,y);
        int tx=p[x].tp,y=p[y].tp;
        ans=max(ans,get2(rt,1,en,p[tx].en,p[x].en));
        x=p[tx].f;
    }
    if(p[x].dp>p[y].dp)
    swap(x,y);
    ans=max(ans,get2(rt,1,en,p[x].en,p[y].en));
    return ans;
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    scanf("%d%d",&w[i],&c[i]);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        ins(x,y);
        ins(y,x);
    }
    dfs1(1,0);
    dfs2(1,1);
    for(int i=1;i<=n;i++)
    {
        root[c[i]]=chg(root[c[i]],1,en,w[i],p[i].en);
    }
    for(int i=0;i<q;i++)
    {
        char s[3];
        int x,y;
        scanf("%s%d%d",s,&x,&y);
        if(s[0]=='C')
        {
            if(s[1]=='C')
            {
                root[c[x]]=del(root[c[x]],1,en,p[x].en);
                c[x]=y;
            }
            else
            w[x]=y;
            root[c[x]]=chg(root[c[x]],1,en,w[x],p[x].en);
        }
        else
        {
            if(s[1]=='S')
            printf("%d\n",slv1(root[c[x]],x,y));
            else
            printf("%d\n",slv2(root[c[x]],x,y));
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值