Codeforces Round #746 (Div. 2) C - Bakry and Partitioning

该博客讨论了一种树形结构的优化问题,给定一棵具有节点权重的树和一个限制值k,询问是否能删除至少一条边,最多k-1条边,使得剩余的连通块中点权的异或和相等。博主分析了当树的异或和为0时总能找到解决方案,并探讨了处理奇数连通块的情况,通过深度优先搜索寻找满足条件的连通块。最后,博主提供了一个C++代码实现来解决这个问题。
摘要由CSDN通过智能技术生成

Bakry and Partitioning

https://codeforces.com/contest/1592/problem/C

题目大意:给出一个有 n n n 个节点的点权树和一个限制 k k k ,现在问能否删除至少一条,至多 k − 1 k-1 k1 条边,使得剩下的连通块里的点权异或和相等。

首先,如果拆分成偶数个连通块,那么我们可以将这偶数个连通块一分为二,合并成异或和相等的两个连通块,那么对于这种情况而言,其整棵树的异或和肯定为 0 0 0 ,而且我们发现如果整颗树异或和为 0 0 0 ,那么其随便切一刀都是相等的两个块。所以如果异或和为 0 0 0 就肯定行。那么主要是讨论奇数情况,那么与偶数类似,如果是奇数块,我们最终可以合并成 3 3 3 块,且显然每一小块的异或和肯定是等于整棵树的异或和的。那么实际上我们只要找到两块不相交的异或和为整树异或和的连通块。如果这样的两个连通块都是子树那就好些了,但是显然不一定是,切成三块必至少有一块为非子树。我们发现,对于非子树的连通块而言,这个连通块下面肯定有颗子树要被切出来,那么我们在深搜的时候就将已经确定为可以切割的子树抹去,实际上也就是另其子树异或值为 0 0 0 ,这样如果上面有原本是非子树的连通块也变成一颗子树了,就可以用一样的方式去计算了,最终只要找到了两个及以上的这样的连通块且 k ≥ 3 k≥3 k3 就表明可以切割。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int n, k, zx[N], a[N], all, cnt;

vector<int> g[N];

void dfs(int u, int fa) {
    zx[u] = a[u];
    for (auto v : g[u]) {
        if (v ^ fa) {
            dfs(v, u);
            zx[u] ^= zx[v];
        }
    }
    if (zx[u] == all) {
        cnt++;
        zx[u] = 0;
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    int T;
    scanf("%d", &T);
    while(T--) {
        all = cnt = 0;
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            all ^= a[i];
            g[i].clear();
        }
        for (int i = 0; i < n - 1; ++i) {
            int u, v;
            scanf("%d%d", &u, &v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dfs(1, 0);
        if (all == 0) {
            puts("YES");
        }
        else if (k - 1 >= 2 && cnt >= 2) {
            puts("YES");
        }
        else {
            puts("NO");
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值