题目
题解
题目条件
①点分了颜色,点的颜色可以随便变。
②询问的是路径。
③子树内点的颜色可以交换。(修改子树)(颜色≤10)
解决方案
很容易想到的一种方法,那就是树链剖分。但是复杂度带2个log,可能会超时。
对于条件③,可以开10棵线段树,同棵线段树中维护着相同颜色的点的权值。
修改子树,询问路径,那么就用括号序来解决问题。
括号序,通俗的讲,就是遍历一遍树走到的点的顺序。那么显然一个点进一次出一次。设
L[x]
表示第一次遍历x时出现的位置。
R[x]
表示最后一次。
整个序列的长度为
2N
。
那么怎么查询路径的点权和?设
sum[i]
表示前缀和,在
L[x]
上加上
weight[x]
,在
R[x]
上减去
weight[x]
。那么
sum[L[x]]
就是根节点到x的权值和。不在这条链上的权值被抵消掉了。
查询一条路径,就是
sum[L[x]]+sum[L[y]]−sum[L[lca(x,y)]]
。
那么对子树内的点颜色交换,可以交换两棵线段树中
L[x]
和
R[x]
之间的区间。
心得
括号序不仅可以维护子树的权值和,也可以维护路径的权值和。
但是这种做法不能够支持链上修改,也不能维护最值。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 100010
#define P(a) putchar(a)
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
struct note{
int ls,rs,sum;
};note tr[N*50];
int c[N],v[N];
struct noe{
int to,next;
};noe edge[N];
int head[N],tot,gs,cnt,root[N];
int L[N],R[N],fa[N][20],dep[N],tar[N];
int i,j,k,n,m,x,y,z,ans,lca;
char ch;
int read(){
int rs=0,fh=1;char ch;
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')fh=-1,ch=getchar();
while(ch>='0'&&ch<='9')rs=rs*10+ch-'0',ch=getchar();
return rs*fh;
}
int write(int x){if(x>9)write(x/10);P(x%10+'0');}
int Write(int x){if(x<0)P('-'),write(x);else write(x);}
void lb(int x,int y){edge[++tot].to=y;edge[tot].next=head[x];head[x]=tot;}
void updt(int ps){
tr[ps].sum=tr[tr[ps].ls].sum+tr[tr[ps].rs].sum;
}
void dg(int x){
L[x]=++gs;tar[gs]=x;
for(int i=head[x];i;i=edge[i].next)
if(edge[i].to!=fa[x][0]){
fa[edge[i].to][0]=x;
dep[edge[i].to]=dep[x]+1;
dg(edge[i].to);
}
R[x]=++gs;tar[gs]=x;
}
int getlca(int x,int y){
int i;
if(dep[x]>dep[y])swap(x,y);
fd(i,19,0)if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
if(x==y)return x;
fd(i,19,0)if(dep[fa[x][i]]!=dep[fa[y][i]])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int query(int ps,int l,int r,int x,int y){
if(!ps)return 0;
if(l==x && r==y)return tr[ps].sum;
int mid=(l+r)>>1;
if(y<=mid)return query(tr[ps].ls,l,mid,x,y);else
if(x>mid)return query(tr[ps].rs,mid+1,r,x,y);else
return query(tr[ps].ls,l,mid,x,mid)+query(tr[ps].rs,mid+1,r,mid+1,y);
}
void change(int &ps,int l,int r,int x,int z){
if(!ps)ps=++gs;
if(l==r){
tr[ps].sum=z;
return;
}
int mid=(l+r)>>1;
if(x<=mid)change(tr[ps].ls,l,mid,x,z);
else change(tr[ps].rs,mid+1,r,x,z);
updt(ps);
}
void exchange(int &px,int &py,int l,int r,int x,int y){
if(!px)px=++gs;
if(!py)py=++gs;
if(l==x && r==y){
swap(px,py);
return;
}
int mid=(l+r)>>1;
if(y<=mid)exchange(tr[px].ls,tr[py].ls,l,mid,x,y);else
if(x>mid)exchange(tr[px].rs,tr[py].rs,mid+1,r,x,y);else
exchange(tr[px].ls,tr[py].ls,l,mid,x,mid),
exchange(tr[px].rs,tr[py].rs,mid+1,r,mid+1,y);
updt(px);
updt(py);
}
int main(){
n=read();
fo(i,1,n)c[i]=read();
fo(i,1,n)v[i]=read();
fo(i,1,n-1){
x=read(),y=read();
x++,y++;
lb(x,y),lb(y,x);
}
gs=0;
dg(1);cnt=gs;
fo(j,1,19)fo(i,1,n)fa[i][j]=fa[fa[i][j-1]][j-1];
gs=0;
fo(i,1,n){
change(root[c[i]],1,cnt,L[i],v[i]);
change(root[c[i]],1,cnt,R[i],-v[i]);
}
m=read();
while(m--){
ch=getchar();
x=read(),y=read(),z=read();
if(ch=='A'){
x++,y++;
lca=getlca(x,y);
ans=query(root[z],1,cnt,1,L[x]);
ans+=query(root[z],1,cnt,1,L[y]);
ans-=query(root[z],1,cnt,1,L[lca]);
Write(ans);
P('\n');
} else
if(ch=='C'){
x++;
exchange(root[y],root[z],1,cnt,L[x],R[x]);
} else{
x++;
fo(i,0,9)
if(query(root[i],1,cnt,L[x],L[x])){
change(root[i],1,cnt,L[x],0);
change(root[i],1,cnt,R[x],0);
break;
}
change(root[y],1,cnt,L[x],z);
change(root[y],1,cnt,R[x],-z);
}
}
return 0;
}