czr 太弱啦
题目描述: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≤2^31−1。
前向星(邻接表的简化式写法)的模板题。。。虽然是看了题解才懂的。那就借此题记录一下前向星的用法吧。
首先,前向星需要一个结构体:
typedef struct
{
int to,next,num;//该边指向的下一个节点,下一条边,该边权值
}STU;
存储一般用一个自定义的add函数,我这里没有用,是直接在主函数里进行的:
int u=0;
for(int i=1;i<n;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);//连接该边的两个点,该边权值
stu[++u].to=y;
stu[u].num=z;
stu[u].next=flag[x];
flag[x]=u;//flag数组用于记录第一个点在哪条边上,起到类似链表的连接作用
stu[++u].to=x;
stu[u].num=z;
stu[u].next=flag[y];
flag[y]=u;
}
前向星的遍历:
for(int i=flag[x];i;i=stu[i].next)
{
if(stu[i].to==fa)
continue;//避免重复计算
dfs(stu[i].to,x,z^stu[i].num);
}
完整代码:
#include<bits/stdc++.h>
using namespace std;
typedef struct
{
int to,next,num;
}STU;
STU stu[10000005];
int flag[1000005];
int n,k;
long long ans=0;
map<int, int>p;//用数组会爆空间
void dfs(int x,int fa,int z)
{
ans=ans+p[z^k];
++p[z];
for(int i=flag[x];i;i=stu[i].next)
{
if(stu[i].to==fa)
continue;
dfs(stu[i].to,x,z^stu[i].num);
}
}
int main()
{
memset(flag,0,sizeof(flag));
scanf("%d%d",&n,&k);
int u=0;
for(int i=1;i<n;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
stu[++u].to=y;
stu[u].num=z;
stu[u].next=flag[x];
flag[x]=u;
stu[++u].to=x;
stu[u].num=z;
stu[u].next=flag[y];
flag[y]=u;
}
dfs(1,1,0);
printf("%lld\n",ans);
return 0;
}