📅  最后修改于: 2023-12-03 15:12:36.475000             🧑  作者: Mango
给定一棵树 $T$,树的根节点为 $1$。现在给定一组询问,每个询问给定两个整数 $u$ 和 $v$,求树上从 $u$ 到 $v$ 的路径中,异或和为偶数的边的数量。
第一行包含一个整数 $n$,表示树的节点数。
接下来 $n-1$ 行,每行包含两个整数 $u$ 和 $v$,表示一条无向边 $(u,v)$。
接下来一行,包含一个整数 $q$,表示询问数量。
接下来 $q$ 行,每行包含两个整数 $u$ 和 $v$,表示一组询问。
对于每个询问,输出一行整数,表示路径中异或和为偶数的边的数量。
$1≤n≤10^5$
$1≤q≤10^5$
$1≤u,v≤n$
对于一条路径的异或和为偶数,等价于这个路径上相邻的两个节点的异或和为偶数,即 $u \oplus v$ 为偶数。
如果考虑一条简单路径 $(1 \rightarrow u \rightarrow v)$,那么它的异或和可以表示为:$1 \oplus dep[u] \oplus dep[v] \oplus u \oplus v$,其中 $dep[x]$ 表示 $x$ 节点的深度。
如果将问题转化为计算一条简单路径的异或和为偶数的边的数量,可以将 $1$ 到 $u$ 的路径和 $1$ 到 $v$ 的路径分别使用前缀异或和求出。如果前缀异或和的异或和为偶数,那么说明这条路径为偶数路径,否则为奇数路径。
使用前缀异或和和哈希映射优化求解时间复杂度
#include <iostream>
#include <cstdio>
#include <cstring>
#include <unordered_map>
using namespace std;
typedef long long LL;
const int N = 100010, M = N * 2;
int n, cnt;
int h[N], e[M], ne[M];
int dep[N], stk[N], top;
LL ans[N];
unordered_map<int, LL> hash[N];
void add(int a, int b)
{
e[cnt] = b, ne[cnt] = h[a], h[a] = cnt ++ ;
}
void dfs(int u, int father)
{
dep[u] = dep[father] + 1;
hash[u][0] = 1;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (j == father) continue;
dfs(j, u);
ans[0] += hash[u][dep[j] & 1 ^ 1] * hash[j][0] + hash[j][dep[u] & 1 ^ 1] * hash[u][0];
if (hash[j].size() > hash[u].size())
{
for (auto& [k, v]: hash[u])
ans[k ^ dep[j] ^ dep[u] ^ 1] += v * hash[j][k];
swap(hash[u], hash[j]);
}
for (auto [k, v]: hash[j]) hash[u][k ^ dep[j] ^ dep[u]] += v;
}
}
int main()
{
scanf("%d", &n);
memset(h, -1, sizeof h);
for (int i = 1; i < n; i ++ )
{
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
add(b, a);
}
dfs(1, 0);
int q;
scanf("%d", &q);
while (q -- )
{
int a, b;
scanf("%d%d", &a, &b);
printf("%lld\n", ans[dep[a] ^ dep[b] & 1]);
}
return 0;
}
代码中使用了哈希映射来优化时间复杂度,具体参考了这个博客:
题解 | GATE CS 2018 | 58. Count Even Length Paths in a Tree - C++ 代码+优化 - shanrenshui891018 - 博客园