因为是求异或值 显然我们需要将val进行二进制拆分 每一位单独去看
由求和式子我们知道 计算点对(u,v)的贡献时 v不能在u的子树中 v不能在 u到根结点的路径上
由于修改都是单点修改 我们可以用树状数组进行差分操作
具体的算法步骤就是:
对于每一个颜色 我们枚举20位
按照操作 顺序 我们将初始值视为一次加操作 将一次修改操作视为一次减操作和一次加操作
计算将要修改的点的每一位的贡献 (用总的减去在子树中的 再减去在根结点到当前点的路径上的 即为满足条件的)
然后进行修改操作
这样的话 ans[0]是由初始值得到的答案 ans[1]到ans[q] 是在前一种情况下的变化值 做一遍前缀和就可以了
#include
using namespace std;
const int N = 1e5+100;
typedef long long ll;
#define pb push_back
vectorto[N];
int n,q;
int val[N],col[N],l[N],r[N],tot,f;
ll ans[N],bt;
inline int in(){
int x=0;char c=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x;
}
struct Que{
int id,x,v,sig;
};
vectorqst[N];
struct bit{
int c[N],n;
void init(int _n){
n=_n+1;
for(int i = 0; i <= n; i++) c[i]=0;
}
void ins(int x,int y){
while(x<=n){
c[x]+=y;
x+=x&-x;
}
}
int query(int x){
int ret=0;
while(x){
ret+=c[x];
x-=x&-x;
}
return ret;
}
int ask(int l,int r){
if(l-1<=0) return query(r);
return query(r)-query(l);
}
}add[2],sub[2];
void dfs(int u,int pre){
l[u]=++tot;
for(auto v:to[u]){
if(v==pre) continue;
dfs(v,u);
}
r[u]=tot;
}
int main(){
int t;
t=in();
while(t--){
n=in();
for(int i = 1; i <= n; i++){
to[i].clear();
qst[i].clear();
}
for(int i = 1; i <= n; i++) col[i]=in();
for(int i = 1; i <= n; i++){
val[i]=in();
qst[col[i]].pb({0,i,val[i],1});
}
for(int i = 1; i < n; i++){
int u,v;
u=in(),v=in();
to[u].pb(v);
to[v].pb(u);
}
tot=0;
dfs(1,0);
q=in();
for(int i = 1; i <= q; i++){
ans[i]=0;
int op,x,v;
op=in(),x=in(),v=in();
if(op==1){
qst[col[x]].pb({i,x,val[x],-1});
val[x]=v;
qst[col[x]].pb({i,x,val[x],1});
}else{
qst[col[x]].pb({i,x,val[x],-1});
col[x]=v;
qst[col[x]].pb({i,x,val[x],1});
}
}
ans[0]=0;
for(int i = 0; i < 2; i++) add[i].init(n),sub[i].init(n);
for(int c = 1; c <= n; c++){
for(int s = 0; s < 20; s++){
ll bit=1ll<>s)&1;
ans[it.id]+=bit*it.sig*(add[f^1].ask(1,n)-
add[f^1].ask(l[it.x],r[it.x])-
(add[f^1].ask(1,l[it.x])+sub[f^1].ask(1,l[it.x]))
);
add[f].ins(l[it.x],it.sig);
sub[f].ins(r[it.x]+1,-it.sig);
}
for(auto it:qst[c]){
f=(it.v>>s)&1;
add[f].ins(l[it.x],-it.sig);
sub[f].ins(r[it.x]+1,it.sig);
}
}
}
for(int i = 1; i <= q; i++) ans[i]+=ans[i-1];
for(int i = 0; i <= q; i++) printf("%lld\n",ans[i]);
}
return 0;
}
/*
5
1
1
1
1
1 1 0
*/