HDU-5416 CRB and Tree
CRB and Tree
思维
路径异或一般考虑预处理从根到所有结点的前缀异或和,然后再进行计算:\(f(u, v) = f(1, u) \oplus f(1, v)\)
初始化后将所有值用桶装起来,然后枚举每一个起点 \(u\),然后终点就是 所询问的异或值 \(s\) \(\oplus\) \(f(1, u)\) 后,所有等于这个值的数量
注意 \(0\) 的情况要在答案上加上一个 \(n\) 再除二
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
const int maxn = 2e5 + 10;
typedef long long ll;
#define pii pair<int, int>
vector<pii>gra[maxn];
int sum[maxn], vis[maxn];
void dfs(int now, int pre)
{
for(pii a : gra[now])
{
if(pre == a.first) continue;
sum[a.first] ^= a.second ^ sum[now];
dfs(a.first, now);
}
vis[sum[now]]++;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n;
scanf("%d", &n);
for(int i=0; i<=n; i++) gra[i].clear();
for(int i=1; i<n; i++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
gra[a].push_back({b, c});
gra[b].push_back({a, c});
}
dfs(1, 1);
int q;
scanf("%d", &q);
while(q--)
{
int x;
scanf("%d", &x);
ll ans = 0;
for(int i=1; i<=n; i++)
ans += vis[x ^ sum[i]];
if(x == 0) ans += n;
printf("%lld\n", ans / 2);
}
for(int i=1; i<=n; i++) {vis[sum[i]] = 0; sum[i] = 0;}
}
return 0;
}