codeforces1592C (dfs,位运算)

1592C

题意:

给定一个有n个节点的树,要求至少删掉一条边,最多删掉k-1条边,使得剩下的连通块的各个节点的异或和相等

思路:

首先考虑异或,假如根节点的异或和为0,那么一定是通过两个相等的值异或得来,也就是说至少删掉一条边,这种情况直接输出yes,考虑其他情况,假如异或和不是0,那么至少要有三个相等的值异或得来,也就是说至少要删掉两条边,所以k=2的时候直接输出no,剩下的情况只要再找到任意两个非根节点并且子树的异或和为总异或和的子树就可以

题解:

#include <bits/stdc++.h>
#define x first
#define y second
#define IOS ios::sync_with_stdio(false);cin.tie(0);
#define lowbit(x) x&(-x)
#define INF 0x7fffffff
#define eb emplace_back
#define divUp(a,b) (a+b-1)/b
#define mkp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define int long long
using namespace std;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);};
bool checkP2(int n) {return n > 0 and (n & (n - 1)) == 0;};
const int N = 100010;
vector<int> h[N];
int w[N];
int n;
int cur = 0;
int cnt = 0;
int dfs(int u, int fa) {
    int ret = w[u];
    for (auto i : h[u]) {
        if (i == fa) continue;
        int s= dfs(i, u);
        if(s==cur) cnt++;
        else ret^=s;
    }
    return ret;
}

void solve() {
    int k;
    cin >> n >> k;
    int u, v;
    cnt = 0, cur = 0;
    for (int i = 1; i <= n; i++) h[i].clear();
    for (int i = 1; i <= n; i++) cin >> w[i], cur ^= w[i];
    for (int i = 1; i < n; i++) {
        cin >> u >> v;
        h[u].eb(v);
        h[v].eb(u);
    }
    dfs(1, -1);
    if (cur == 0) {
        cout << "YES" << endl;
        return;
    }
    if (cur and k == 2) {
        cout << "NO" << endl;
        return;
    }
    if (cnt >= 2) cout << "YES" << endl;
    else cout << "NO" << endl;
}
signed main() {
    IOS;
    int _; cin >> _; while (_--) solve();
    return 0;
}
posted @ 2021-10-04 23:42  指引盗寇入太行  阅读(48)  评论(0编辑  收藏  举报