题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5416
解题思路:
官方题解:
We can easily proved that f(u,v) = f(1,u) ^f(1,v).
Traversing tree from vertex 1 as the root, all values f(1,u) can be calculated in linear time. These values must be put into buckets.
For each query s, f(u,v) = s⇔f(1,v) = f(1,u)^ s indicates that for each vertex u, number of vertices v satisfies that f(u,v) = s can be calculated from the buckets in constant time. (Note that some exceptions must be processed such as s = 0 or u = v)
Time complexity:O(Q⋅N)
设路径{u,v}的边权异或结果为 f(u,v)
设lca 为u v的最近公共祖先
首先得到一个结论,f(u,v) =f(lca, u) ^ f(lca, v)
因为f(lca, root) ^ f(lca, root) == 0
所以 f(u,v) =( f(lca,u)^f(lca,root) ) ^ ( f(lca, v) ^ f(lca, root)) = f(root,u) ^ f(root, v)
然后用一个数组存下从根到任意一个点的路径异或值。
最后对每个询问,枚举以某个点为端点的路径个数即可。
因为这样算出来的path(u,v)是计算了2遍的,所以结果要/2
注意一下0的情况即可。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 100005;
const int maxn = N<<1;
struct node{
int x,w;
};
vector<node> edge[N];
int vis[N];
ll cnt[maxn];
void dfs(int u,int val){
vis[u] = 1;
if(u^1)
cnt[val]++;
int l = edge[u].size();
for(int i = 0; i < l; i++){
node tmp = edge[u][i];
if(!vis[tmp.x]){
dfs(tmp.x,tmp.w^val);
}
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
int n,q;
scanf("%d",&n);
for(int i = 1; i <= n; i++)
edge[i].clear();
int u,v,w;
for(int i = 1; i < n; i++){
scanf("%d%d%d",&u,&v,&w);
edge[u].push_back(node{v,w});
edge[v].push_back(node{u,w});
}
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
dfs(1,0);
scanf("%d",&q);
while(q--){
scanf("%d",&w);
ll ans = 0;
if(w == 0){
ans += n+cnt[0];
for(int i = 0; i < maxn; i++)
ans += cnt[i] * (cnt[i] - 1) / 2;
}
else{
for(int i = 0; i < maxn; i++)
ans += cnt[i] * (cnt[i ^ w]);
ans >>= 1;
ans += cnt[w];
}
printf("%lld\n",ans);
}
}
return 0;
}