题目描述
czr太弱啦!他现在小学组题目都不会做,于是来求助你。
问题是:给定一棵树,问路径的异或和等于k的有几条?
形式化描述:给定一棵N个节点组成的有边权的无根树,你需要计数这样的正整数对(u,v)(1≤u≤v≤n),满足若从u到v经过的路径上的边权依次为w1,w2,…,wL,那么w1 xor w2 xor…xor wL =k。其中“xor”表示非负整数按位取异或。
输入
第1行:两个正整数n,k,含义见题面描述。
第2∼n行:每一行包含三个正整数u,v,w,代表节点u、v之间存在一条权值为w的边。节点从1开始编号。
输出
第1行:一个正整数——所有路径中异或和为k的路径条数。
样例输入
5 0
4 3 7
5 1 4
3 2 7
5 4 7
样例输出
2
提示
有2–3–4、3–4–5共2条路径上的边权异或和为k=0。
对于所有测试数据,所有权值w满足0≤w≤231−1。
思路
给了5s的时限,建树暴力求解即可,由于xor具有x xor z xor y xor z= k 的性质,因此只需要从任意根节点出发,求解时查询已经该数xork求得的数量即可
代码实现
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+10;
const int mod=1e9+7;
const int INF=0x3f3f3f;
typedef pair<int,int> P;
struct edge
{
int v,index,val;
}Edge[N];
int n,head[N];
int cnt,k;
ll ans;
bool vis[N];
map<int,int> p;
void add(int u,int v,int val)
{
Edge[++cnt].v=v;
Edge[cnt].index=head[u];
Edge[cnt].val=val;
head[u]=cnt;
}
void dfs(int x,int nu)
{
if(vis[x]) return ;
vis[x]=true;
ans=ans+p[nu^k];
p[nu]++; //记录与k异或相同的数字
for(int i=head[x];i;i=Edge[i].index)
{
int v=Edge[i].v;
dfs(v,nu^Edge[i].val);
}
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w),add(v,u,w);
}
dfs(1,0);
printf("%lld\n",ans);
return 0;
}