CF1709E
设 valu 表示树中 1 到 u 路径上的点权异或和。
那么 u 到 v 路径上的点权异或和为 0 说明 valu⊕valv⊕alca(u,v)=0。
不难发现因为值域没有限制,所以改变了点 u 的点权之后,一定不存在以 u 子树中的点为端点的点权异或和为 0 的路径。
那么对每个点开一个 set
,保存其子树中 val 的集合。如果最终一个点必须被修改,那么它的 set
就变成空的。
设当前点为 u,u 的当前集合为 S,它的某个儿子的集合为 T,枚举 T 中每个元素 x,如果 S 中存在 au⊕x,那么最终 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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话