SPOJ COT3 - Combat on a tree

/*
考虑直接使用暴力来算的话   SG[i]表示以i为根的子树的SG值, 然后考虑枚举删除那个子树节点, 然后求拆成的树的sg异或值, 求mex即可 复杂度三次方

然后考虑尝试 整体来做 发现对于每次子树的合并, 每棵子树种的sg值相当是异或了其他的所有子树

而这个东西显然是可以用 线段树合并来维护的

最后找出所有sg不为0的点即可

*/
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
#define ll long long
#define M 100010
#define mmp make_pair
using namespace std;
int read() {
    int nm = 0, f = 1;
    char c = getchar();
    for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0';
    return nm * f;
}
int cor[M], cov[M * 60], laz[M * 60], ls[M * 60], rs[M * 60], rt[M], n, sg[M], cnt, ans[M], tot;
vector<int> to[M];

void add(int &now, int v, int deep) {
    if(deep <= -1) return;
    if(v & (1 << deep)) swap(ls[now], rs[now]);
    laz[now] ^= v;
}

void pushdown(int now, int deep) {
    if(!laz[now] || !now) return;
    add(ls[now], laz[now], deep - 1);
    add(rs[now], laz[now], deep - 1);
    laz[now] = 0;
}

int merge(int now, int last, int deep) {
    if(!now || !last) return now | last;
    if(deep == -1) {
        cov[now] |= cov[last];
        return now;
    }
    pushdown(now, deep), pushdown(last, deep);
    ls[now] = merge(ls[now], ls[last], deep - 1);
    rs[now] = merge(rs[now], rs[last], deep - 1);
    cov[now] = cov[ls[now]] && cov[rs[now]];
    return now;
}

void insert(int &now, int v, int deep) {
    if(!now) now = ++cnt;
    if(deep == -1) {
        cov[now] = 1;
        return;
    }
    if(v & (1 << deep)) insert(rs[now], v, deep - 1);
    else insert(ls[now], v, deep - 1);
}

int mex(int now, int deep) {
    if(!now || deep == -1) return 0;
    pushdown(now, deep);
    if(!cov[ls[now]]) return mex(ls[now], deep - 1);
    else return (1 << deep) + mex(rs[now], deep - 1);
}

void dfs(int now, int fa) {
    int tmp = 0;
    for(int i = 0; i < to[now].size(); i++) {
        int vj = to[now][i];
        if(vj == fa) continue;
        dfs(vj, now);
        tmp ^= sg[vj];
    }
    if(!cor[now]) insert(rt[now], tmp, 17);
    for(int i = 0; i < to[now].size(); i++) {
        int vj = to[now][i];
        if(vj == fa) continue;
        add(rt[vj], tmp ^ sg[vj], 17);
        rt[now] = merge(rt[now], rt[vj], 17);
    }
    sg[now] = mex(rt[now], 17);
}

void get(int now, int fa, int anss) {
    for(int i = 0; i < to[now].size(); i++) {
        int vj = to[now][i];
        if(vj == fa) continue;
        anss ^= sg[vj];
    }
    if(anss == 0 && !cor[now]) ans[++tot] = now;
    for(int i = 0; i < to[now].size(); i++) {
        int vj = to[now][i];
        if(vj == fa) continue;
        get(vj, now, anss ^ sg[vj]);
    }
}


int main() {
    n = read();
    for(int i = 1; i <= n; i++) cor[i] = read();
    for(int i = 1; i < n; i++) {
        int vi = read(), vj = read();
        to[vi].push_back(vj);
        to[vj].push_back(vi);
    }
    dfs(1, 0);
    get(1, 0, 0);
    if(tot) {
        sort(ans + 1, ans + tot + 1);
        for(int i = 1; i <= tot; i++) cout << ans[i] << '\n';
    } else puts("-1");
    return 0;
}



上一篇:leetcode(84)柱状图中最大的矩形


下一篇:「重庆市NOIP模拟赛」独立集