[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
原文地址:https://www.cnblogs.com/Joker-Yza/p/11402838.html