码迷,mamicode.com
首页 > 其他好文 > 详细

[SPOJ COT3] SG函数 Trie树 线段树合并

时间:2017-07-28 19:23:16      阅读:177      评论:0      收藏:0      [点我收藏+]

标签:getc   tar   int   git   9.png   image   com   线段树   log   

题目

  技术分享

 

分析

  技术分享

  技术分享

 

实现

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <vector>
using namespace std;

#define F(i, a, b) for (register int i = (a); i <= (b); i++)
#define fore(it, x) for (register vector<int>::iterator it = g[x].begin(); it != g[x].end(); it++)

const int N = 100005;
const int B = 20;
const int S = 3000000;

int n, col[N];
vector<int> g[N];

int f[N], rt[N], tot;
int c[S][2], tag[S]; bool full[S];

bool s[N];

inline int rd(void) {
    int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1;
    int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-0; return x*f;
}

inline void Push(int x, int w, int bit) {
    if (x > 0) {
        if (w >> bit & 1)
            swap(c[x][0], c[x][1]);
        tag[x] ^= w;
    }
}
inline void Clear(int x, int bit) {
    if (!tag[x]) return;
    Push(c[x][0], tag[x], bit-1);
    Push(c[x][1], tag[x], bit-1);
    tag[x] = 0;
}
inline void Merge(int &x, int y, int bit) {
    if (!x) { x += y; return; }
    if (bit == -1) { full[x] |= full[y]; return; }
    Clear(x, bit);
    Clear(y, bit);
    Merge(c[x][0], c[y][0], bit-1);
    Merge(c[x][1], c[y][1], bit-1);
    full[x] = full[c[x][0]] & full[c[x][1]];
}
inline void Insert(int &x, int bit, int w) {
    if (!x) x = ++tot;
    if (bit == -1) { full[x] = true; return; }
    Clear(x, bit);
    Insert(c[x][w >> bit & 1], bit-1, w);
    full[x] = full[c[x][0]] & full[c[x][1]];
}
inline int Mex(int x, int bit) {
    if (!x || bit == -1) return 0;
    Clear(x, bit);
    return full[c[x][0]] ? (1<<bit) + Mex(c[x][1], bit-1) : Mex(c[x][0], bit-1);
}

void Solve(int x, int pre) {
    fore(it, x) if (*it != pre)
        Solve(*it, x);
    
    int sum = 0; fore(it, x) if (*it != pre) sum ^= f[*it];
    fore(it, x) if (*it != pre) {
        Push(rt[*it], sum ^ f[*it], B);
        Merge(rt[x], rt[*it], B);
    }
    if (!col[x]) Insert(rt[x], B, sum);
    
    f[x] = Mex(rt[x], B);
}
void Find(int x, int pre, int tar) {
    int sum = 0; fore(it, x) if (*it != pre) sum ^= f[*it];
    if (!col[x] && sum == tar) s[x] = true;
    fore(it, x) if (*it != pre)
        Find(*it, x, tar ^ sum ^ f[*it]);
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("game.in", "r", stdin);
        freopen("game.out", "w", stdout);
    #endif
    
    n = rd();
    F(i, 1, n) col[i] = rd();
    F(i, 1, n-1) {
        int x = rd(), y = rd();
        g[x].push_back(y), g[y].push_back(x);
    }
    
    Solve(1, -1);
    
    if (!f[1]) puts("-1");
    else {
        Find(1, -1, 0);
        //    F(i, 1, n) printf("%d\n", f[i]);
        F(i, 1, n) if (s[i]) printf("%d\n", i);
    }
    
    return 0;
}

 

[SPOJ COT3] SG函数 Trie树 线段树合并

标签:getc   tar   int   git   9.png   image   com   线段树   log   

原文地址:http://www.cnblogs.com/Sdchr/p/7251799.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!