[BZOJ3553] [SHOI2014]三叉神经树
Description
计算神经学作为新兴的交叉学科近些年来一直是学术界的热点。一种叫做SHOI 的神经组织因为其和近日发现的化合物 SHTSC 的密切联系引起了人们的极大关注。
SHOI 组织由若干个 SHOI 细胞构成,SHOI 细胞之间形成严密的树形结构。
每个 SHOI 细胞都有且只有一个输出端,被称为轴突,除了一个特殊的、被称为根细胞的 SHOI 细胞的输出作为整个组织的输出以外,其余细胞的轴突均连向其上级 SHOI 细胞;并且有且只有三个接收端,被称为树突,从其下级细胞或者其它神经组织那里接收信息。SHOI 细胞的信号机制较为简单,仅有 0 和 1 两种。每个 SHOI 细胞根据三个输入端中 0 和 1 信号的多寡输出较多的那一种。
现在给出了一段 SHOI 组织的信息,以及外部神经组织的输入变化情况。请你模拟 SHOI 组织的输出结果。
Input
第一行一个整数:n。表示 SHOI 组织的总细胞个数。SHOI 细胞由 1~n 编号,编号为 1 的是根细胞。
从第二行开始的 n 行,每行三个整数 x1, x2, x3,分别表示编号为 1~n 的 SHOI 细胞的树突连接。1<xi≤n 表示连向编号为 xi 的细胞的轴突, n<xi≤3n+1 表示连向编号为 xi 的外界输入。输入数据保证给出的 SHOI 组织是合法的且所有的 xi 两两不同。
接下来一行 2n+1 个 0/1 的整数,表示初始时的外界输入。
第 n+3 行有一个整数:q,表示总操作数。
之后 q 行每行一个整数 x,表示编号为 x 的外界输入发生了变化。
Output
输出 q 行每行一个整数,对应第 i 次外界输入变化后的根细胞的输出。
Sample Input
3
2 3 4
5 6 7
8 9 10
0 0 0 0 1 1 1
5
4
4
5
6
8
Sample Output
1
0
0
1
1
Solution
设\(val[i],i\leqslant n\)表示这个点有多少个值为\(1\)的儿子,那么这个点的值就是\([val[i]\geqslant 2]\)。
注意到一个比较显然的性质:
- 对于每次修改,设当前是把\(0\)变\(1\),那么我们必然是把一段从叶子开始向上延伸的,\(val[i]\)全为\(1\)的链变为\(2\),在把链上方的一个点改掉。
- 另一种情况就是\(2\)变\(1\)。
那么就可以考虑用一种数据结构来维护这个。
这里选用\(LCT\)来维护,对于\(splay\)上的每个点维护一个\(c_1[i]\)表示当前重链最深的\(val\ne 1\)的点,同理维护\(c_2[i]\)表示\(val\ne 2\)的点。
那么每次修改就直接打个标记覆盖一下就好了。
注意这题由于\(n\)比较大,数据还丧心病狂的有一堆的链,写递归貌似会爆栈,反正我本机会爆栈。
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
const int maxn = 1.6e6+10;
int n,m,top;
queue<int > q;
int r[maxn],l[maxn],d[maxn],sta[maxn];
int son[maxn][2],fa[maxn],c1[maxn],c2[maxn],tag[maxn],val[maxn];
int which(int x) {return son[fa[x]][1]==x;}
int is_root(int x) {return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;}
#define ls son[x][0]
#define rs son[x][1]
void update(int x) {
c1[x]=c1[rs]?c1[rs]:(val[x]!=1?x:c1[ls]);
c2[x]=c2[rs]?c2[rs]:(val[x]!=2?x:c2[ls]);
}
void push_tag(int x,int t) {swap(c1[x],c2[x]);tag[x]+=t;val[x]^=3;}
void pushdown(int x) {
if(!tag[x]) return ;
push_tag(ls,tag[x]),push_tag(rs,tag[x]),tag[x]=0;
}
void rotate(int x) {
int y=fa[x],z=fa[y],w=which(x);
if(!is_root(y)) son[z][son[z][1]==y]=x;
fa[x]=z,fa[y]=x,fa[son[x][w^1]]=y,son[y][w]=son[x][w^1],son[x][w^1]=y;
update(y),update(x);
}
void push(int x) {if(!is_root(x)) push(fa[x]);pushdown(x);}
void splay(int x) {
top=0;int t=x;while(!is_root(t)) sta[++top]=t,t=fa[t];sta[++top]=t;
while(top) pushdown(sta[top--]);
for(;!is_root(x);rotate(x)) if(!is_root(fa[x])) rotate(which(fa[x])==which(x)?fa[x]:x);
update(x);
}
void access(int x) {for(int y=0;x;splay(x),son[x][1]=y,update(y=x),x=fa[x]);}
int main() {
read(n);int now;
for(int i=1;i<=n;i++)
for(int j=1,x;j<=3;j++)
read(x),fa[x]=i,d[x]=3;
for(int i=n+1;i<=n*3+1;i++) read(r[i]),q.push(i);
for(int v;!q.empty();) {
v=q.front(),q.pop();
if((v>n&&r[v])||val[v]>=2) val[fa[v]]++;
if(!--d[fa[v]]) q.push(fa[v]);
}
read(m);now=val[1]>=2;
for(int i=1,x;i<=m;i++) {
read(x);int t=r[x]?-1:1;r[x]^=1;
access(x=fa[x]);splay(x);
int v=~t?c1[x]:c2[x];
if(!v) now^=1,push_tag(x,t),update(x);
else splay(x=v),push_tag(rs,t),update(rs),val[x]+=t,update(x);
putchar(now|48);puts("");
}
return 0;
}