zoukankan      html  css  js  c++  java
  • [SHOI2014]三叉神经树——LCT

    题面:

      LOJ#2187

    解析:

       显然修改一次需要修改一条到根的链, 维护链当然就想到用LCT了

      结果就想偏了, 本来想分别维护虚子树信息与整棵子树信息,结果发现很难维护。然后去自学了一发

      我们定义一个点的点权为它的儿子节点中选$1$的个数

      考虑更改一个点的点权要么对它上方的链中连续的$1$或连续$2$, 因此Splay中每个节点分别维护能到的最深的不是$1$的点与不是$2$的点,然后是一个区间修改和单点修改了,直接在Splay中搞就行了

      注意更新父亲节点时的顺序,先用右儿子更新,再用左儿子

     代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn = 500004, inf = 0x3f3f3f3f;
    
    inline int read()
    {
        int ret, f = 1;
        char c;
        while((c=getchar())&&(c<'0'||c>'9'))if(c=='-')f = -1;
        ret=c-'0';
        while((c=getchar())&&(c>='0'&&c<='9')) ret = (ret<<3)+(ret<<1)+c-'0';
        return ret*f;
    }
    
    int n, m, f[maxn<<1], a[maxn<<1], root, ans;
    bool vis[maxn];
    
    struct LCT{
        int fa, s[2], val;
        int nd1, nd2, add;
    }tr[maxn]; 
    
    int head[maxn], tot; 
    struct edge{
        int nxt, to;
    }e[maxn]; 
    
    void Addedge(int x, int y)
    {
        e[++tot] = (edge){head[x], y};
        head[x] = tot;
    }
    
    void dfs(int x)
    {
        for(int i = head[x]; i; i = e[i].nxt)
        {
            int id = e[i].to;
            dfs(id);
            tr[x].val += (tr[id].val > 1);
        }
        tr[x].nd1 = (tr[x].val != 1? x: inf);
        tr[x].nd2 = (tr[x].val != 2? x: inf);
    }
    
    void update(int x)
    {
        int ls = tr[x].s[0], rs = tr[x].s[1];
        if(rs && tr[rs].nd1 != inf)
            tr[x].nd1 = tr[rs].nd1;
        else if(tr[x].val != 1)
            tr[x].nd1 = x;
        else if(ls) 
            tr[x].nd1 = tr[ls].nd1;
        else 
            tr[x].nd1 = inf;
    
        if(rs && tr[rs].nd2 != inf)
            tr[x].nd2 = tr[rs].nd2;
        else if(tr[x].val != 2)
            tr[x].nd2 = x;
        else if(ls) 
            tr[x].nd2 = tr[ls].nd2;
        else 
            tr[x].nd2 = inf;
    }
    
    void spread(int x)
    {
        int ls = tr[x].s[0], rs = tr[x].s[1];
        if(tr[x].add)
        {
            if(ls)
            {
                tr[ls].add += tr[x].add;
                tr[ls].val += tr[x].add;
                swap(tr[ls].nd1, tr[ls].nd2);
            }
            if(rs)
            {
                tr[rs].add += tr[x].add;
                tr[rs].val += tr[x].add;
                swap(tr[rs].nd1, tr[rs].nd2);
            }
            tr[x].add = 0;    
        }
    }
    
    bool isroot(int x)
    {
        int ff = tr[x].fa;
        return tr[ff].s[0] != x && tr[ff].s[1] != x;
    }
    
    void Rotate(int x)
    {
        int y = tr[x].fa, z = tr[y].fa, k = (tr[y].s[1] == x), w = (tr[z].s[1] == y), son = tr[x].s[k^1];
        if(!isroot(y))
            tr[z].s[w] = x;
        tr[y].s[k] = son;tr[son].fa = y;
        tr[x].s[k^1] = y;tr[y].fa = x;
        tr[x].fa = z;
        update(y);update(x);
    }
    
    void PushDown(int x)
    {
        if(!isroot(x))    PushDown(tr[x].fa);
        spread(x);
    }
    
    void Splay(int x)
    {
        int y, z;
        PushDown(x);
        while(!isroot(x))
        {    
            y = tr[x].fa;
            z = tr[y].fa;
            if(!isroot(y))
                Rotate((tr[y].s[0] == x) ^ (tr[z].s[0] == y)? x: y);
            Rotate(x);
        }
    }
    
    void Access(int x)
    {
        int pre = 0;
        while(x)
        {
            Splay(x);
            tr[x].s[1] = pre;
            update(x);
            pre = x;
            x = tr[x].fa;
        }
    }
    
    int main()
    {
        n = read();
        for(int i = 1; i <= n; ++i)
        {
            int x;
            for(int j = 1; j <= 3; ++j)
            {
                x = read();
                if(x <= n)
                {
                    tr[x].fa = i;
                    Addedge(i, x);
                    vis[x] = 1;
                }
                else
                    f[x-n] = i;
            }
        }
        for(int i = 1; i <= (n<<1) + 1; ++i)
            a[i] = read(), tr[f[i]].val += a[i];
        for(int i = 1; i <= n; ++i)
            if(!vis[i])
            {
                root = i;
                dfs(i);
                break;
            }
        ans = (tr[root].val > 1);
        m = read();
        for(int i = 1; i <= m; ++i)    
        {
            int x = read();
            x -= n;
            Access(f[x]);
            Splay(f[x]);
            int now = (a[x] == 0? tr[f[x]].nd1: tr[f[x]].nd2), c = (a[x] == 0? 1: -1);
            if(now != inf)
            {
                Splay(now);
                tr[now].val += c;
                int rs = tr[now].s[1];
                if(rs)
                {
                    tr[rs].val += c;
                    tr[rs].add += c;
                    swap(tr[rs].nd1, tr[rs].nd2);
                    update(rs);
                }
                update(now);
            }
            else
            {
                tr[f[x]].val += c;
                tr[f[x]].add += c;
                ans ^= 1;
            }
            a[x] ^= 1;
            printf("%d
    ", ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Confluence 6 使用 LDAP 授权连接一个内部目录概述
    Confluence 6 导入 Active Directory 服务器证书
    Confluence 6 导入 Active Directory 服务器证书
    Confluence 6 导入 Active Directory 服务器证书
    Confluence 6 获得 Active Directory 服务器证书
    Confluence 6 安装 Active Directory 证书服务器
    Confluence 6 为 Active Directory 配置一个 SSL 连接预要求
    Confluence 6 为 Active Directory 配置一个 SSL 连接
    内容社交产品中的关键数据——获得良好反馈的用户比例
    基于Redis+Kafka的首页曝光过滤方案
  • 原文地址:https://www.cnblogs.com/Joker-Yza/p/11402838.html
Copyright © 2011-2022 走看看