题意:一棵树上,每个点有颜色和权值,多个更改和询问,求某种颜色在一条路径上的最大值或和。
题解:树剖,每种颜色开一个线段树,动态开点就好了。
代码:
#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));
}
}
}