hdu5416
题目
给你一棵树,树上两点的f值就是他们路径上边权的异或,现在给定s,求f值等于s的点对。
思路
由于异或两次相当于没有异或,我们记录每个点到根节点的路径异或值,对于任意两点之间的路径异或值只要吧到根节点的值异或一下就可以了,最后相当于枚举符合情况的个数,如果s=0,还要把不走的n个情况加上去。(maxn大小开的不一样会WA,不知道为什么。。。)
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
int n;
struct node
{
int next;
int to;
int w;
} edge[maxn*2];
int head[maxn],tot;
ll cur[2*100010];
void addedge(int from,int to,int w)
{
edge[tot].to=to;
edge[tot].w=w;
edge[tot].next=head[from];
head[from]=tot++;
}
void dfs(int u,int fa,int d)
{
for(int i=head[u]; ~i; i=edge[i].next)
{
int v=edge[i].to;
int w=edge[i].w;
if(v==fa) continue;
cur[w^d]++;
dfs(v,u,w^d);
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
memset(head,-1,sizeof(head));
tot=0;
memset(cur,0,sizeof(cur));
for(int i=0; i<n-1; i++)
{
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
dfs(1,-1,0);
int q;
scanf("%d",&q);
cur[0]++;
while(q--)
{
ll ans=0;
int s;
scanf("%d",&s);
for(int i=0; i<maxn; i++)
{
if((s^i)==i) ans+=(ll)cur[i]*(cur[i]-1);
else ans+=(ll)cur[i]*cur[s^i];
}
ans/=2;
if(s==0)
ans+=n;
printf("%I64d\n",ans);
}
}
return 0;
}