czr 太弱啦

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值