CF1709E

valu 表示树中 1u 路径上的点权异或和。

那么 uv 路径上的点权异或和为 0 说明 valuvalvalca(u,v)=0

不难发现因为值域没有限制,所以改变了点 u 的点权之后,一定不存在以 u 子树中的点为端点的点权异或和为 0 的路径。

那么对每个点开一个 set,保存其子树中 val 的集合。如果最终一个点必须被修改,那么它的 set 就变成空的。

设当前点为 uu 的当前集合为 S,它的某个儿子的集合为 T,枚举 T 中每个元素 x,如果 S 中存在 aux,那么最终 u 就必须被修改。

时间复杂度 O(n2logn),启发式合并 set 就能做到时间复杂度 O(nlog2n),空间复杂度 O(nlogn)

Code:

#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int n;
int a[N], val[N];
int head[N], ver[N*2], nxt[N*2], cnt;
int ans;
set <int> S[N];

void add(int u, int v) {
	ver[++cnt] = v, nxt[cnt] = head[u], head[u] = cnt;
}

void dfs(int u, int fa) {
	bool flag = 0; S[u].insert(val[u]);
	for (int i = head[u]; i; i = nxt[i]) {
		int v = ver[i];
		if (v == fa) continue;
		val[v] = val[u] ^ a[v], dfs(v, u);
		if (S[u].size() < S[v].size()) swap(S[u], S[v]);
		for (auto x : S[v]) if (S[u].find(a[u] ^ x) != S[u].end()) flag = 1;
		for (auto x : S[v]) S[u].insert(x);
	}
	if (flag) ++ans, S[u].clear();
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
	for (int i = 1, u, v; i < n; ++i) scanf("%d%d", &u, &v), add(u, v), add(v, u);
	val[1] = a[1], dfs(1, 0);
	printf("%d", ans);
	return 0;
}
posted @   Kobe303  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示