题目描述
计算神经学作为新兴的交叉学科近些年来一直是学术界的热点。一种叫做SHOI 的神经组织因为其和近日发现的化合物 SHTSC 的密切联系引起了人们的极大关注。
SHOI 组织由若干个 SHOI 细胞构成,SHOI 细胞之间形成严密的树形结构。每个 SHOI 细胞都有且只有一个输出端,被称为轴突,除了一个特殊的、被称为根细胞的 SHOI 细胞的输出作为整个组织的输出以外,其余细胞的轴突均连向其上级 SHOI 细胞;并且有且只有三个接收端,被称为树突,从其下级细胞或者其它神经组织那里接收信息。SHOI 细胞的信号机制较为简单,仅有 00和 11两种。每个 SHOI 细胞根据三个输入端中 00和 11信号的多寡输出较多的那一种。
现在给出了一段 SHOI 组织的信息,以及外部神经组织的输入变化情况。请你模拟 SHOI 组织的输出结果。
思路:
如果能改变一个细胞输出, 那么这个细胞的值一定是 1, 或者 2,
所以我们要维护一个从底部开始第一个不是1 或者2 的位置,然后修改就可以了.
每次修改都是修改连续的 1 ,或者连续的 0.
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+100;
int tag[N<<2],val[N<<2],f[N<<2],ch[N<<2][2],hep[N<<2],rev[N<<2],dep1[N<<2],dep2[N<<2];
int n,m,du[N];
inline int isroot(int x) {
return ch[f[x]][0] != x && ch[f[x]][1] != x;
}
void pushup(int x){ //优先找右子树.
dep1[x] = dep1[ch[x][1]];
if (!dep1[x] && val[x] != 1) dep1[x] = x;
if (!dep1[x]) dep1[x] = dep1[ch[x][0]];
dep2[x] = dep2[ch[x][1]];
if (!dep2[x] && val[x] != 2) dep2[x] = x;
if (!dep2[x]) dep2[x] = dep2[ch[x][0]];
}
void solve(int x, int d){
if (!x) return;
val[x] ^= 3;
swap(dep2[x],dep1[x]);
tag[x] += d;
}
void pushdown(int x){
if (!tag[x]) return ;
solve(ch[x][0],tag[x]);
solve(ch[x][1], tag[x]);
tag[x] = 0;
}
inline void rotate(int x){
int y = f[x], z = f[y], k = ch[y][1] == x, v = ch[x][!k];
if (!isroot(y)) ch[z][ch[z][1] == y] = x;//Attention if()
ch[x][!k] = y; ch[y][k] = v;
if (v) f[v] = y;
f[y] = x, f[x] = z;
pushup(y); pushup(x);
}
inline void splay(int x){
int y = x, top = 0; hep[++top] = y;
while(!isroot(y)) hep[++top] = y = f[y]; //这里个splay 不同之处,用一个栈存下来节点.
while(top) pushdown(hep[top--]); //然后一个一个的从上往下pushdown .
while(!isroot(x)){
y = f[x]; top = f[y];
if (!isroot(y))
rotate((ch[y][0] == y) ^ (ch[top][0] == y)?x:y);
rotate(x);
}
pushup(x);
}
inline void access(int x){
for(int y = 0; x; x = f[y = x])
splay(x), ch[x][1] = y, pushup(x);
}
void init(){
int x,y,z;
queue<int>q;
scanf("%d",&n);
for (int i = 1; i <= n; ++i){
scanf("%d%d%d",&x,&y,&z);
f[x] = f[y] = f[z] = i;
du[i] = 3;
}
// val[i] 代表每个点的权值,然后 val[i] >> 1 就是要输出的值,
for (int i = n+1; i <= 3*n+1; ++i){
scanf("%d",&x); val[i] = x * 2; q.push(i); //这里为了方便运算,所以叶子节点的值也都 *2.
}
while(!q.empty()){ //这里是确定每个点的val值.
int u = q.front(); q.pop();
int v = f[u];
if (u <= n) pushup(u);
val[v] += val[u]/2;
du[v]--;
if (du[v] == 0) q.push(v);
}
}
int main(){
int x;
init();
int ans = val[1] >> 1;
scanf("%d",&m);
for (int i = 0; i < m; ++i){
scanf("%d",&x);
val[x] ^= 2; //一开始 val 的值就 * 2 了, 所以val 的值只有两种可能, 0 或者 2.
int k = val[x] - 1; // k 的值是确定 +1 还是 -1.
x = f[x];
access(x); splay(x); //首先 从 x 的父亲拉一条链出来.
int now;
if (k == -1) now = dep2[x]; else now = dep1[x]; //要更新的点在 x 和 now之间.
if (!now) {
solve(x,k); pushup(x); //代表更新整条链.
ans ^= 1;
} else{ // 找到要更新的区间.splay一下,然后更新.
splay(now);
solve(ch[now][1],k); //更新右子树.
pushup(ch[now][1]); //更新完之后,向上合并.
val[now] += k; // 这个节点单独更新. 这个节点的值不是 1 或者 2.
pushup(now); // 向上合并.
}
printf("%d\n",ans);
}
return 0;
}