题目:http://acm.hdu.edu.cn/showproblem.php?pid=5416
题意:定给一棵树,有N-1条边,每条边有一个权值,查询两个点u到v的异或和为s的路的条数(u可以等于v)。
分析:预处理出所有的顶点到root的异或和,然后对于每次查询枚举起点就行了。
代码:
#include <iostream> #include <cstdio> #include <map> #include <cstring> using namespace std; const int maxn = 1e5+6; struct node { int v,w,next; }List[maxn<<2]; int Table[maxn],cnt,fa[maxn],N; int mp[maxn<<1]; void Insert(int u,int v,int w) { List[cnt].v=v; List[cnt].w=w; List[cnt].next=Table[u]; Table[u]=cnt++; } void dfs(int cur,int value) { int p=Table[cur]; while(~p) { if(List[p].v!=fa[cur]) { mp[value^List[p].w]++; fa[List[p].v]=cur; dfs(List[p].v,value^List[p].w); } p=List[p].next; } } long long ans,s; void solve(int cur,int value) { ans+=mp[value^s]; int p=Table[cur]; while(~p) { if(List[p].v!=fa[cur]) solve(List[p].v,List[p].w^value); p=List[p].next; } } int main() { int ncase,i,j,u,v,w,Q,x; scanf("%d",&ncase); while(ncase--) { scanf("%d",&N); cnt=0; memset(Table,-1,sizeof(Table)); memset(fa,-1,sizeof(fa)); for(i=1;i<N;i++) { scanf("%d%d%d",&u,&v,&w); Insert(u,v,w); Insert(v,u,w); } memset(mp,0,sizeof(mp)); mp[0]=1; dfs(1,0); scanf("%d",&Q); while(Q--) { scanf("%lld",&s); ans=0; if(s==0) ans=N; solve(1,0); printf("%lld\n",ans>>1); } } return 0; }