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

BZOJ4134: ljw和lzr的hack比赛

时间:2015-06-16 20:58:57      阅读:479      评论:0      收藏:0      [点我收藏+]

标签:

每次操作实际上相当于把点到根上所有点消除。$O({n^2})$暴力显然,

用trie维护每棵子树的后继局面,然后需要进行trie树异或操作和tire树合并操作。

异或操作直接打标记

合并操作前,类似启发式合并,先把子树较小的的标记全部下放,然后全部按照另一棵的标记转好,然后把它合并到另一颗里面去。正确性因为有标记的地方都转过,再转一次就是原来的了。

合并类似线段树合并

复杂度$O(nlogn)$

技术分享
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define drep(i, r, l) for (int i = r; i >= l; i--)
typedef long long ll;
const int N = 100008, D = 20;
int n, TOT, head[N], tot, fa[N], sg[N], a[N], rt[N], ans[N];
bool rev[N][D + 5];
struct Edge{int next, node;}e[N << 1];
int xgw;
inline void add(int x, int y)
{
    e[++TOT].next = head[x], head[x] = TOT, e[TOT].node = y;
    e[++TOT].next = head[y], head[y] = TOT, e[TOT].node = x;
}
struct Node
{
    int s[2], sum, sz;
}t[N * (D + 5)];
inline void updata(int x)
{
    t[x].sum = t[t[x].s[0]].sum + t[t[x].s[1]].sum;
    t[x].sz = 1 + (t[x].s[0] ? 1 : 0) + (t[x].s[1] ? 1 : 0);
}
void Insert(int u, int x, int d, int num)
{
    if (!d) {t[x].sum = 1; return;}
    int p = (num & (1 << d - 1)) ? 1 : 0;
    p ^= rev[u][d];
    if (!t[x].s[p]) t[x].s[p] = ++tot;
    Insert(u, t[x].s[p], d - 1, num);
    updata(x);
}
void calc(int u, int d, int num)
{
    if (!rt[u]) return;
    rep(i, 1, d) rev[u][i] ^= (num & (1 << i - 1)) ? 1 : 0;
}
int Find(int u, int x, int d, int cur)
{
    if (!x || !d) return cur;
    int ls = t[x].s[0 ^ rev[u][d]], rs = t[x].s[1 ^ rev[u][d]];
    //if (xgw) printf("->%d %d %d %d\n", u, d, t[ls].sum, t[rs].sum);
    if (t[ls].sum != (1 << d - 1)) 
        return Find(u, ls, d - 1, cur);
    return Find(u, rs, d - 1, cur + (1 << d - 1));
}
void Turn(int u, int x, int d)
{
    if (!d || !x) return;
    if (rev[u][d]) swap(t[x].s[0], t[x].s[1]);
    Turn(u, t[x].s[0], d - 1);
    Turn(u, t[x].s[1], d - 1);
}
int Merge(int u, int x, int v, int y, int d)
{
    if (!d) return x;
    if (!x || !y) return x + y;
    rep(i, 0, 1) 
    {
        int j = i ^ rev[u][d], k = i ^ rev[v][d];
        t[x].s[j] = Merge(u, t[x].s[j], v, t[y].s[k], d - 1);
    }
    updata(x);
    return x;
}
int MERGE(int u, int v)
{
    if (t[rt[u]].sz > t[rt[v]].sz) swap(u, v);
    Turn(u, rt[u], D);
    memcpy(rev[u], rev[v], sizeof(rev[v]));
    Turn(u, rt[u], D);
    return Merge(v, rt[v], u, rt[u], D);    
}
void write(int u, int x, int d, int cur)
{
    if (!x) return;
    if (!d) {printf("%d ", cur); return;}
    int ls = t[x].s[0 ^ rev[u][d]], rs = t[x].s[1 ^ rev[u][d]];
    write(u, ls, d - 1, cur);
    write(u, rs, d - 1, cur + (1 << d - 1));
}
void dfs(int u)
{
    int Leaf = 1;
    for (int i = head[u], v; v = e[i].node, i; i = e[i].next)
        if (v != fa[u])
            Leaf = 0, fa[v] = u, dfs(v);
    if (Leaf) 
    {
        sg[u] = !a[u]; 
        if (sg[u]) Insert(u, rt[u] = ++tot, D, 0);  
        return;
    }
    int x = 0;
    for (int i = head[u], v; v = e[i].node, i; i = e[i].next)
        if (v != fa[u])
        {
            calc(u, D, sg[v]); calc(v, D, x);            
            rt[u] = MERGE(u, v);
            x ^= sg[v];
        }
    if (!a[u]) Insert(u, rt[u] ? rt[u] : rt[u] = ++tot, D, x);
    sg[u] = Find(u, rt[u], D, 0);
}
void Tour(int u, int cur)
{
    cur ^= sg[u];
    for (int i = head[u], v; v = e[i].node, i; i = e[i].next)
        if (v != fa[u]) cur ^= sg[v];
    if (!a[u] && !cur) ans[++ans[0]] = u;
    for (int i = head[u], v; v = e[i].node, i; i = e[i].next)
        if (v != fa[u]) Tour(v, cur);
}
void solve()
{
    dfs(1);
    //rep(i, 1, n) printf("[%d %d]\n", i, sg[i]);
    if (!sg[1]) printf("-1\n");
    else 
    {
        Tour(1, sg[1]);
        sort(ans + 1, ans + ans[0] + 1);
        rep(i, 1, ans[0]) printf("%d\n", ans[i]); 
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
#endif
    scanf("%d", &n);
    rep(i, 1, n) scanf("%d", &a[i]);
    rep(i, 1, n - 1)
    {
        int u, v; 
        scanf("%d%d", &u, &v);
        add(u, v);
    }
    solve();
#ifndef ONLINE_JUDGE
    fclose(stdin); fclose(stdout);
#endif
    return 0;
}
View Code

 

BZOJ4134: ljw和lzr的hack比赛

标签:

原文地址:http://www.cnblogs.com/Dyzerjet/p/4581676.html

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