Processing math: 100%

[BZOJ3553] [SHOI2014]三叉神经树

0|1Description


计算神经学作为新兴的交叉学科近些年来一直是学术界的热点。一种叫做SHOI 的神经组织因为其和近日发现的化合物 SHTSC 的密切联系引起了人们的极大关注。
SHOI 组织由若干个 SHOI 细胞构成,SHOI 细胞之间形成严密的树形结构。
每个 SHOI 细胞都有且只有一个输出端,被称为轴突,除了一个特殊的、被称为根细胞的 SHOI 细胞的输出作为整个组织的输出以外,其余细胞的轴突均连向其上级 SHOI 细胞;并且有且只有三个接收端,被称为树突,从其下级细胞或者其它神经组织那里接收信息。SHOI 细胞的信号机制较为简单,仅有 0 和 1 两种。每个 SHOI 细胞根据三个输入端中 0 和 1 信号的多寡输出较多的那一种。
现在给出了一段 SHOI 组织的信息,以及外部神经组织的输入变化情况。请你模拟 SHOI 组织的输出结果。

0|1Input


第一行一个整数: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 的外界输入发生了变化。

0|1Output


输出 q 行每行一个整数,对应第 i 次外界输入变化后的根细胞的输出。

0|1Sample Input


3 
2 3 4 
5 6 7 
8 9 10 
0 0 0 0 1 1 1 
5 
4 
4 
5 
6 
8 

0|1Sample Output


1
0
0
1
1

0|1Solution


val[i],in表示这个点有多少个值为1的儿子,那么这个点的值就是[val[i]2]

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

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

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

这里选用LCT来维护,对于splay上的每个点维护一个c1[i]表示当前重链最深的val1的点,同理维护c2[i]表示val2的点。

那么每次修改就直接打个标记覆盖一下就好了。

注意这题由于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;
}

__EOF__

作  者Hyscere
出  处https://www.cnblogs.com/hbyer/p/10475881.html
关于博主:编程路上的小学生,热爱技术,喜欢专研。评论和私信会在第一时间回复。或者直接私信我。
版权声明:署名 - 非商业性使用 - 禁止演绎,协议普通文本 | 协议法律文本
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!

posted @   Hyscere  阅读(180)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示