1. 程式人生 > >[SPOJ COT3] SG函數 Trie樹 線段樹合並

[SPOJ COT3] SG函數 Trie樹 線段樹合並

swa 線段 std line etc 分析 eight sin stdout

題目

  技術分享

分析

  技術分享

  技術分享

實現

#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樹 線段樹合並