Description
一棵树,每个节点有权值和颜色。询问有一下几种:
- 询问从u到v的路径上与u相同颜色的节点的权值和(保证u与v颜色相同)
- 询问从u到v的路径上与u相同颜色的节点的权值的MAX(保证u与v颜色相同)
- 修改节点v的权值
- 修改节点v的颜色
Analysis
若不考虑颜色,那么这就是一个裸的链剖(链剖裸题)。
在线做法
由于还没有搞出来,留坑待填。
离线大法
首先,我们要高呼:离线大法好!离线大法好!离线大法好!
我们可以把相同颜色类型的操作排序在一起,操作原顺序为第二关键字。
把修改颜色操作看成是添加一个节点,到下一组颜色时为了不影响,应该再删除此节点。预处理也要看成是操作,也要拆成添加和删除。这样经过我们的转换后,各个颜色的操作之间就不影响了,变成了裸的链剖,就直接用线段树维护即可。
Key Code
fo(i,1,n)
{
scanf("%d %d\n",&a[i],&c[i]);
b[++Q].tp=2,b[Q].x=i,b[Q].y=a[i],b[Q].id=Q,b[Q].c=c[i];
}
fo(i,1,n-1)
{
scanf("%d %d\n",&u,&v);
link(u,v),link(v,u);
}
dfs1(1,0,1);
dfs2(1,0,1);
char ch;
fo(i,1,_)
{
scanf("%c%c %d %d\n",&ch,&ch,&x,&y);
b[++Q].x=x,b[Q].y=y,b[Q].id=Q,b[Q].ps=i;
if(ch=='S') b[Q].tp=0,bz[i]=1;
else
if(ch=='M') b[Q].tp=1,bz[i]=1;
else
if(ch=='W') b[Q].tp=2,a[x]=y;
else
{
b[Q].tp=2,b[Q].c=y,b[Q].y=a[x];
b[++Q].tp=2,b[Q].x=x,b[Q].y=0,b[Q].id=Q,b[Q].c=c[x];
c[x]=y;
continue;
}
b[Q].c=c[x];
}
fo(i,1,n) b[++Q].tp=2,b[Q].x=i,b[Q].y=0,b[Q].id=Q,b[Q].c=c[i];
sort(b+1,b+Q+1,cmp);
fo(i,1,Q)
{
if(b[i].tp<2) ans[b[i].ps]=solve(b[i].x,b[i].y,b[i].tp);
else change(1,1,n,w[b[i].x],b[i].y);
}
fo(i,1,_)
if(bz[i]) printf("%d\n",ans[i]);