题解: CF1824C(LuoTianyi and XOR-Tree)

Link

1. Description

给定一棵 \(n\) 个节点的树,根节点为 \(1\),每个点有一个点权 \(a_i\),每次操作可以选择一个点任意修改点权,求最少的操作次数,使得每一条根结点到叶子结点的路径上的异或和都为 \(0\)

2. Solution

我果然理解不了锦依卫们的思路

此时不妨设 \(val(u,v)\) 表示 \(u\)\(v\) 的路径上,所有点点权的异或和,\(leaf_u\) 表示以 \(u\) 为根的子树中,所有叶子结点的编号构成的集合,\(son_u\) 表示 \(u\) 的所有子节点构成的集合。

此时我们考虑一个树形 DP,定义 \(f_{u,x}\) 表示使得 \(\forall v\in leaf_y,val(v,u)=x\) 的操作次数最小值,那么 \(f_{u,x}={\min\limits_{i=1}^V([i\ne x]+\sum_{v\in son_u}f_{v,i})}\),这样就可以得到时间复杂度为 \(O(nV)\) 的做法。

而显然有这样一个结论:当以 \(u\) 为根的子树中,满足 \(\forall v\in lead_u,val(v,u)\) 均相等,那么我们可以通过更改 \(u\) 的点权,使得所有 \(val(v,u)\) 变成任意一个我们想要的值。

这个结论带来的结果就是如果我们记 \(mi=\min\limits_{i=1}^V \{f_{u,x}\}\),那么对于任意的 \(x\in [1,V]\)\(f_{u,x}\in \{mi,mi+1\}\)

这个结果很有意思,对于一个节点,我们只需要记录 \(mi,S\),用来表示使得 \(\forall v\in lead_u,val(v,u)\) 均相等的操作次数,和在这样的限制下可以达到的相同的值的集合,就可以表示这个点的 \(dp\) 值,而这样,我们的转移就变得简单了起来。

这个时候记录 \(cnt_x\) 表示 \(x\) 这个值在 \(S_v,v\in son_u\) 中出现了几次,\(mx=\max\limits_{i=1}^V (cnt_i)\),那么 \(mi_u=|son_u|-mx+\sum_{v\in son_u} mi_v\)

这样,我们就可以用启发式合并来维护 \(mi_u\)\(S_u\) 了。

最后统计答案,只需要看看 \(S_1\) 中有没有 \(0\),如果有,那么答案为 \(mi_1\),否则,答案为 \(mi_1+1\)

3. Code

/*by qwer6*/
/*略去快读快写与缺省源*/
const int N=1e5+5;
int n;
int siz[N],son[N],bel[N],val[N],tag[N],f[N];
bool leaf[N];
unordered_map<int,int>cnt;
set<int>st[N],now;
vector<int>e[N];
void dfs(int u,int fa){
	siz[u]=1;
	for(int v:e[u]){
		if(v==fa)continue;
		dfs(v,u);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]])son[u]=v; 
	}
	if(siz[u]==1)leaf[u]=1;
}
void redfs(int u,int fa){
	if(leaf[u]){
		bel[u]=u;
		tag[u]=val[u];
		st[u].insert(0);
		return ;
	}
	int cntson=0;
	for(int v:e[u]){
		if(v==fa)continue;
		cntson++;
		redfs(v,u);
		f[u]+=f[v];
	}
	if(cntson==1){
		bel[u]=bel[son[u]],tag[u]=tag[son[u]]^val[u];
		return ;
	}
	cnt.clear();
	now.clear();
	int mx=0,idx,tmp;
	for(int v:e[u]){
		if(v==fa||v==son[u])continue;
		idx=bel[v];
		for(int x:st[idx]){
			tmp=x^tag[v];
			if(now.count(tmp))cnt[tmp]++;
			else{
				now.insert(tmp);
				cnt[tmp]=1;
			}
			tomax(mx,cnt[tmp]);
		}
		st[idx].clear();
	}
	idx=bel[son[u]];
	for(int x:now){
		tmp=x^tag[son[u]];
		if(st[idx].count(tmp)){
			cnt[x]++;
			tomax(mx,cnt[x]);
		}
	}
	f[u]+=cntson-mx;
	if(mx>1){
		bel[u]=u,tag[u]=val[u];
		for(int x:now)
			if(cnt[x]==mx)st[u].insert(x);
	}else{
		bel[u]=bel[son[u]],tag[u]=tag[son[u]]^val[u];
		for(int x:now)st[bel[u]].insert(x^tag[son[u]]);
	}
}
signed main(){
	read(n);
	for(int i=1;i<=n;i++)read(val[i]);
	for(int i=2,u,v;i<=n;i++){
		read(u),read(v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs(1,0);
	redfs(1,0);
	if(st[bel[1]].count(tag[1]))write(f[1]);
	else write(f[1]+1);
}
posted @ 2025-05-17 21:53  陈牧九  阅读(14)  评论(0)    收藏  举报