[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],ileqslant n)表示这个点有多少个值为(1)的儿子,那么这个点的值就是([val[i]geqslant 2])

注意到一个比较显然的性质:

  • 对于每次修改,设当前是把(0)(1),那么我们必然是把一段从叶子开始向上延伸的,(val[i])全为(1)的链变为(2),在把链上方的一个点改掉。
  • 另一种情况就是(2)(1)

那么就可以考虑用一种数据结构来维护这个。

这里选用(LCT)来维护,对于(splay)上的每个点维护一个(c_1[i])表示当前重链最深的(val e 1)的点,同理维护(c_2[i])表示(val e 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('
');}

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;
}
原文地址:https://www.cnblogs.com/hbyer/p/10475881.html