棒子出的题目,统计一下两点间所有边的值的抑或值为k的有多少,思路很简单,运用了抑或运算的一些性质,因为一条路走两次最后的抑或值为0,对结果没有影响所以可以将题意转化为从一个顶点走到根节点再从根节点走到另外一个点,这样只需要用树形dp统计一下从根节点到其他节点的值的个数就可以了,这样最后再做一下遍历就可以结束。
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <functional>
#include <cstdio>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <utility>
typedef long long ll;
using namespace std;
const int mx = 100009;
const int N = mx * 2;
int head[mx],cnt;
ll num[mx << 1];
struct node
{
int next,to,w;
} edge[mx << 1];
void add(int x,int y,int w)
{
edge[cnt].to = y;
edge[cnt].w = w;
edge[cnt].next = head[x];
head[x] = cnt++;
}
void dfs(int x,int u,int c)
{
int i;
num[c]++;
for(i = head[x]; i != -1; i = edge[i].next)
if(edge[i].to != u)
dfs(edge[i].to,x,c ^ edge[i].w);
}
int main ()
{
int n,m,T,i,j,x,y,z,q;
ll ans,k;
scanf("%d",&T);
while(T--)
{
memset(head,-1,sizeof(head));
memset(num,0,sizeof(num));
cnt = 0;
scanf("%d",&n);
for(i = 1; i <n; i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
dfs(1,0,0);
scanf("%d",&q);
while(q--)
{
ans = 0;
scanf("%lld",&k);
for(i = 0; i < N; i++)
if((i ^ k) < N)
ans = ans + num[i] * num[i ^ k];
if(!k)
ans = ans + n;
ans = ans >> 1;
printf("%lld\n",ans);
}
}
}