[SHOI2014]三叉神经树——LCT
作者:互联网
题面:
解析:
显然修改一次需要修改一条到根的链, 维护链当然就想到用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\n", ans); } return 0; }View Code
标签:LCT,rs,int,tr,nd1,fa,三叉神经,ls,SHOI2014 来源: https://www.cnblogs.com/Joker-Yza/p/11402838.html