#Trie#洛谷 6018 [Ynoi2010] Fusion tree

题目

给定一棵树,树上每个节点都有点权,需要实现三种操作,

第一种是将与 \(x\) 相邻的所有节点点权加一,第二种是单点减小点权,

第三种是查询与 \(x\) 相邻的所有节点点权的异或和


分析

相邻实际上就是父节点和子节点,不妨将其拆开考虑,

需要解决单点查询单点修改的问题,考虑维护 \(n\) 棵 Trie 求子节点异或和

由低位到高位建树,实际上 \(w=(w_0 \oplus w_1)\times 2+[cnt_1\ is\ odd]\)

加一实际上就是进位的问题,那么 \(1,11,111,\dots\) 结尾的数都会变成零,

实际上就是 \(trie[p][0]\)\(trie[p][1]\) 的交换

然后 \(1\) 为根节点而没有父节点,直接单独维护即可,时间复杂度 \(O(n\log a_i)\)


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int N=1234567; struct node{int y,next;}e[N];
int fat[N],as[N],et=1,n,Q,tot,rt[N],a[N],trie[N*20][2],c[N*20],ed[N*20],w[N*20],fa[N*20];
int iut(){
	int ans=0,f=1; char c=getchar();
	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans*f; 
}
void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
void dfs(int x,int fa){
	fat[x]=fa;
	for (int i=as[x];i;i=e[i].next)
	    if (e[i].y!=fa) dfs(e[i].y,x);
}
void update(int rt,int x,int i,int opt){
	if (opt==-1){
		--c[ed[i]];
		for (int p=ed[i];fa[p];p=fa[p],--c[p])
			w[fa[p]]=(w[trie[fa[p]][0]]^w[trie[fa[p]][1]])<<1|(c[trie[fa[p]][1]]&1);
		ed[i]=0;
	}else{
		for (int j=0;j<20;++j){
		    int z=x&1; x>>=1;
		    if (!trie[rt][z]) trie[rt][z]=++tot;
		    fa[trie[rt][z]]=rt,rt=trie[rt][z];
	    }
		++c[ed[i]=rt];
		for (int p=ed[i];fa[p];p=fa[p],++c[p])
			w[fa[p]]=(w[trie[fa[p]][0]]^w[trie[fa[p]][1]])<<1|(c[trie[fa[p]][1]]&1);
	}
}
void plusone(int rt){
	swap(trie[rt][0],trie[rt][1]);
	if (trie[rt][0]) plusone(trie[rt][0]);
	w[rt]=(w[trie[rt][0]]^w[trie[rt][1]])<<1|(c[trie[rt][1]]&1);
}
int query(int x){
	int ans=0;
	for (int p=ed[x];fa[p];p=fa[p])
	if (trie[fa[p]][1]==p) ans=ans<<1|1;
	    else ans<<=1;
	return ans;
}
int main(){
	n=iut(),Q=iut();
	for (int i=1;i<n;++i){
		int x=iut(),y=iut();
		e[++et]=(node){y,as[x]},as[x]=et;
		e[++et]=(node){x,as[y]},as[y]=et;
	}
	dfs(1,0),tot=n;
	for (int i=1;i<=n;++i) rt[i]=i;
	for (int i=1;i<=n;++i){
		a[i]=iut();
		if (fat[i]) update(rt[fat[i]],a[i],i,1);
	}
	for (int i=1;i<=Q;++i)
	switch (iut()){
		case 1:{
			int x=iut();
			if (fat[x]==1) ++a[1];
			else if (fat[fat[x]]){
				int z=query(fat[x]);
				update(rt[fat[fat[x]]],z,fat[x],-1);
				update(rt[fat[fat[x]]],z+1,fat[x],1);
			}
			plusone(rt[x]);
			break;
		}
		case 2:{
			int x=iut(),y=iut();
			if (x==1) a[x]-=y;
			else{
				int z=query(x);
				update(rt[fat[x]],z,x,-1);
				update(rt[fat[x]],z-y,x,1);
			}
			break;
		}
		case 3:{
			int x=iut(),z=w[rt[x]];
			if (fat[fat[x]]) z^=query(fat[x]);
			    else if (fat[x]==1) z^=a[1];
			print(z),putchar(10);
			break;
		}
	}
	return 0;
}
posted @ 2024-05-10 17:18  lemondinosaur  阅读(10)  评论(0编辑  收藏  举报