*题解:P6018 [Ynoi2010] Fusion tree

题目链接

解析

对父亲单独处理,问题变为序列整体加 \(1\),序列单点加,求异或和。直接建 Trie 难以维护整体加 \(1\),但事实上我们可以对每个结点倒着建一个从低位往高位走的 Trie,这样加 \(1\) 就变成了交换连向两棵子树的边权并向交换前边权为 \(1\) 的那条边走,递归重复此过程。

实现上,在 Trie 上维护一个子树异或和和子树大小,push_up 时,若边权为 \(1\) 的那条边连接的子树的大小为奇数,则异或和的该位为 \(1\),否则为 \(0\)。除此之外,由于我们单独处理了父亲,而整体加 \(1\) 会影响操作点 \(x\) 的所有儿子的儿子的父亲,所以需要在 \(x\) 处记录该位置上进行了多少次操作 \(1\),对于父亲单点加,对父亲的父亲的 Trie 进行修改即可。

时间复杂度 \(O((n + m)\log a)\)

代码

#include<bits/stdc++.h>
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
#define mid ((l + r) >> 1)
#define getchar() getchar_unlocked()
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef pair<int,int> pii;
const int N = 5e5 + 5,M = 19; 
int rt[N],son[N * M][2],sum[N * M],siz[N * M],cnt;
int ocnt[N],val[N];
vector<int> t[N];
int fa[N];
void push_up(int x,int k){
	siz[x] = siz[son[x][0]] + siz[son[x][1]];
	sum[x] = (siz[son[x][1]] % 2 == 0 ? 0 : (1 << k)) | (sum[son[x][0]] ^ sum[son[x][1]]);
}
void insert(int &x,int val,int k){
	if(!x) x = ++cnt;
	if(k == M - 1){
		siz[x]++;
		return;
	}
	insert(son[x][bool(val & (1 << k))],val,k + 1);
	push_up(x,k);
}
void erase(int &x,int val,int k){
	if(k == M - 1){
		siz[x]--;
		return;
	}
	erase(son[x][bool(val & (1 << k))],val,k + 1);
	push_up(x,k);
}
void add1(int &x,int k){
	if(!x) return;
	swap(son[x][0],son[x][1]);
	add1(son[x][0],k + 1);
	push_up(x,k);
}
void dfs(int x,int f){
	fa[x] = f;
	for(int nx : t[x])if(nx != f){
		dfs(nx,x);
		insert(rt[x],val[nx],0);
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);	
//	freopen("in.txt","r",stdin);
//	freopen("out1.txt","w",stdout);
	int n,m;
	cin>>n>>m;
	for(int i=1;i<n;i++){
		int u,v;
		cin>>u>>v;
		t[u].push_back(v);
		t[v].push_back(u);
	}
	for(int i=1;i<=n;i++){
		cin>>val[i];
	}
	dfs(1,0);
	while(m--){
		int op,x,v;
		cin>>op>>x;
		if(op == 1){
			add1(rt[x],0);
			ocnt[x]++;
			if(fa[x]){
				int ff = fa[fa[x]];
				if(ff){
					erase(rt[ff],val[fa[x]] + ocnt[ff],0);
				}
				val[fa[x]]++;
				if(ff){
					insert(rt[ff],val[fa[x]] + ocnt[ff],0);
				}
			}
		}else if(op == 2){
			cin>>v;
			if(fa[x]){
				erase(rt[fa[x]],val[x] + ocnt[fa[x]],0);
			}
			val[x] -= v;
			if(fa[x]){
				insert(rt[fa[x]],val[x] + ocnt[fa[x]],0);
			}
		}else{
			int res = sum[rt[x]];
			int k = 0;
			if(fa[x]){
				k += val[fa[x]];
				if(fa[fa[x]]){
					k += ocnt[fa[fa[x]]];
				}
			}
			res ^= k;
			cout<<res<<'\n';
		}
	}
	return 0;
}
posted @ 2026-09-03 18:55  yutar  阅读(9)  评论(0)    收藏  举报