HDU Tokitsukaze and Colorful Tree 离线+树状数组

因为是求异或值 显然我们需要将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
*/

 

你可能感兴趣的:(HDU,多校,树状数组)