牛客练习赛32 B题:Xor Path 树上结点贡献次数

本文探讨了一种解决特定树形结构上节点权值异或和问题的算法。通过树形DP技术,我们计算了所有节点对之间的路径上节点权值的异或和总贡献。算法核心在于统计每个节点在所有路径中的出现频率,将其分为两部分:作为路径一部分和其他节点作为路径起始点。此方法避免了直接计算每条路径的复杂度。
摘要由CSDN通过智能技术生成

题意:

给定一颗n个结点的树(n-5e5),每个结点有个权值ai(ai-1e9)

现在定义一个值 path[i][j] 表示i结点到j结点最短路径上 经过的所有结点权值的异或和

现在要求计算所有的 path[i][j] 异或和,i 范围1~n-1, j 范围 i+1 ~ n

思路:

首先树上最短路径是唯一的,即两个点只有一条路径(每个点只能走一次的话);

然后考虑到计算所有path值的异或和的时候,我们会发现,最后的答案就是每跳路径中经过的点的权值的异或和

然后我们可以算每个结点在所有路径中出现的次数,也就是算他的贡献次数,

至于这个点贡献了多少次,可以分为两部分:一部分是在其他两点路径上,另一部分是这个点作为path的开头

第一部分的值就是这个点连接的每个点及后面的点看作子树,和另外的所有的点算一下,相当于贡献次数,每个结点都算

第二部分都是n-1次;

 

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

const ll mod = 1e9 + 7;
const ll maxn = 1e6 + 7;


ll n;
vector<ll> vec[maxn];
ll a[maxn];
ll ans = 0;

ll dfs(ll id, ll f) {
    ll sum = 0;
    ll t = 0;
    ll res = 1; // 子树大小
    for(auto i : vec[id]) {
        if(i == f) continue;
        t = dfs(i, id);
        res += t;
        sum += (t*(n-t-1)); //sum %= 2LL;
    }
    sum += (n-res)*(res-1); sum /= 2LL;//sum %= 2LL;
    sum += (n-1); sum %= 2LL;
    if(sum&1) ans ^= a[id];
    return res;
}

int main() {
    scanf("%lld", &n);
    for(int i = 1; i < n; ++i) {
        ll x, y; scanf("%lld%lld", &x, &y);
        vec[x].push_back(y);
        vec[y].push_back(x);
    }
    for(int i = 1; i <= n; ++i) {
        scanf("%lld", &a[i]);
    }

    int x = dfs(1, -1);
    printf("%lld", ans);

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值