zoukankan      html  css  js  c++  java
  • BZOJ4134: ljw和lzr的hack比赛

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

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

    异或操作直接打标记

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

    复杂度$O(nlog^2n)$

    #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
    ", 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]
    ", i, sg[i]);
        if (!sg[1]) printf("-1
    ");
        else 
        {
            Tour(1, sg[1]);
            sort(ans + 1, ans + ans[0] + 1);
            rep(i, 1, ans[0]) printf("%d
    ", 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
  • 相关阅读:
    centos网卡一致性命名规则
    CloudBoot裸机部署服务器
    vmware-nic teaming
    电商 Excel 列 连接,类似SQL里面的 join
    Layui 多选
    电商工具 谷歌插件 版本 2021-06-11
    电商工具 谷歌插件 数据抓取 数据下载 生意参谋的访客数据、淘宝后台订单、主图、详情图、评论、物流、直通车数据
    其它 VS Code 配置选中的文字
    C# 跨域
    PS 字体的使用
  • 原文地址:https://www.cnblogs.com/Dyzerjet/p/4581676.html
Copyright © 2011-2022 走看看