HDU ACM 5416 CRB and Tree DFS+前缀跟
HDU ACM 5416 CRB and Tree DFS+前缀和
题意:在一棵树上有n个点,n-1条边,每条边都有一个权值。
令f(u,v)等于u到v这条路径上的异或和。
现在给你Q次询问(Q<=10)
题意:在一棵树上有n个点,n-1条边,每条边都有一个权值。
令f(u,v)等于u到v这条路径上的异或和。
现在给你Q次询问(Q<=10)
询问f(u,v)=s的路径有多少条。
分析:Q比较小,可直接用O(n)复杂度来做。
先用sum[u]保存下,从根节点到u的异或和是多少。
用一个hash map来保存,sum[u]出现了多少次。
每次就查询hash map中s ^ sum[u]出现了多少次。
查询的总和除以2就是最终结果。
X^Y=S;X^S=Y;X^Y^X=Y。
注意:
如果s=0时,f(u,u)也满足条件,所以还要再加上n。结果会超32位int。
#include<iostream> #include<vector> using namespace std; #define maxn ((int)2e5+10) struct edge { edge(){} edge(int _u,int _v,int _val):u(_u),v(_v),val(_val){} int u,v,val; }; int sum[maxn],MAP[maxn]; //异或和及hash MAP vector<edge> G[maxn]; //树 int n,q; void init() { int i; memset(MAP,0,sizeof(MAP)); for(i=1;i<=n;i++) G[i].clear(); } void add_edge(int u,int v,int val) { G[u].push_back(edge(u,v,val)); } void dfs(int u,int pre,int val) { int i,v; sum[u]=val; for(i=0;i<G[u].size();i++) { v=G[u][i].v; if(v==pre) continue; dfs(v,u,val^G[u][i].val); } } __int64 cal(int s) { __int64 ans=0,i; for(i=1;i<=n;i++) ans+=MAP[s^sum[i]]; if(s==0) ans+=n; return ans/2; } int main() { int T; int u,v,val,s,i; scanf("%d",&T); while(T--) { scanf("%d",&n); init(); for(i=1;i<n;i++) { scanf("%d%d%d",&u,&v,&val); add_edge(u,v,val); add_edge(v,u,val); } dfs(1,-1,0); for(i=1;i<=n;i++) MAP[sum[i]]++; scanf("%d",&q); while(q--) { scanf("%d",&s); printf("%I64d\n",cal(s)); } } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。