洛谷传送门
BZOJ传送门
题目描述
计算神经学作为新兴的交叉学科近些年来一直是学术界的热点。一种叫做SHOI 的神经组织因为其和近日发现的化合物 SHTSC 的密切联系引起了人们的极大关注。
SHOI 组织由若干个 SHOI 细胞构成,SHOI 细胞之间形成严密的树形结构。每个 SHOI 细胞都有且只有一个输出端,被称为轴突,除了一个特殊的、被称为根细胞的 SHOI 细胞的输出作为整个组织的输出以外,其余细胞的轴突均连向其上级 SHOI 细胞;并且有且只有三个接收端,被称为树突,从其下级细胞或者其它神经组织那里接收信息。SHOI 细胞的信号机制较为简单,仅有 和 两种。每个 SHOI 细胞根据三个输入端中 和 信号的多寡输出较多的那一种。
现在给出了一段 SHOI 组织的信息,以及外部神经组织的输入变化情况。请你模拟 SHOI 组织的输出结果。
输入输出格式
输入格式:
输入的第一行包含一个整数 。表示 SHOI 组织的总细胞个数。SHOI 细胞由 编号,编号为 的是根细胞。
从第二行开始的 行,每行三个整数 ,分别表示编号为 的 SHOI 细胞的树突连接。 表示连向编号为 的细胞的轴突, 表示连向编号为 的外界输入。输入数据保证给出的 SHOI 组织是合法的,且所有的 两两不同。
接下来一行包含 个 的整数,表示初始时的外界输入。
第 行有一个整数 ,表示总操作数。
之后 行每行一个整数 ,表示编号为 的外界输入发生了变化。
输出格式:
输出 行,每行一个整数,对应第 次外界输入变化后的根细胞的输出。
输入输出样例
输入样例#1:
3
2 3 4
5 6 7
8 9 10
0 0 0 0 1 1 1
5
4
4
5
6
8
输出样例#1:
1
0
0
1
1
说明
对于 的数据, 。
对于 的数据, 。
对于 的数据, 。
解题分析
可以发现, 每次更改最底层的结果会改变自底向上的一条链上连续 的结果, 更具体地说, 设 为 号节点的权值, 那么改变的是自底部开始的 的一部分。
那么我们直接用 维护链上从下向上第一个权值不为 的位置, 在修改的时候直接 后找到这个位置, 再区间打一个修改 就好了。
注意如果到根节点都没有要求的点, 直接修改答案, 在根节点上打 。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <algorithm>
#include <queue>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 500500
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
std::queue <int> q;
int n, m, top;
int sta[MX], deg[MX];
struct Node {int son[2], fat, p1, p2, val, tag;} tree[MX << 2];
namespace LCT
{
#define ls tree[now].son[0]
#define rs tree[now].son[1]
#define dad tree[now].fat
IN bool get(R int now) {return tree[dad].son[1] == now;}
IN bool nroot(R int now) {return tree[dad].son[1] == now || tree[dad].son[0] == now;}
IN void pushup(R int now)
{
if (!tree[rs].p1)
{
if (tree[now].val != 1) tree[now].p1 = now;
else tree[now].p1 = tree[ls].p1;
} else tree[now].p1 = tree[rs].p1;
if (!tree[rs].p2)
{
if (tree[now].val != 2) tree[now].p2 = now;
else tree[now].p2 = tree[ls].p2;
} else tree[now].p2 = tree[rs].p2;
}
IN void pushtag(R int now, R int del)
{
tree[now].tag += del;
tree[now].val ^= 3;
std::swap(tree[now].p1, tree[now].p2);
}
IN void pushdown(R int now)
{
if (tree[now].tag)
pushtag(ls, tree[now].tag), pushtag(rs, tree[now].tag), tree[now].tag = 0;
}
IN void rotate(R int now)
{
R int fa = dad, grand = tree[fa].fat;
R bool dir = get(now);
tree[fa].son[dir] = tree[now].son[dir ^ 1];
tree[tree[now].son[dir ^ 1]].fat = fa;
tree[now].fat = grand;
if (nroot(fa)) tree[grand].son[get(fa)] = now;
tree[now].son[dir ^ 1] = fa;
tree[fa].fat = now;
pushup(fa);
}
IN void splay(R int now)
{
int tmp = now, fa;
sta[top = 1] = now;
W (nroot(now)) sta[++top] = now = dad;
W (top) pushdown(sta[top--]);
now = tmp;
W (nroot(now))
{
fa = dad;
if (nroot(fa)) rotate(get(fa) == get(now) ? fa : now);
rotate(now);
}
pushup(now);
}
IN void access(R int now)
{
for (R int x = 0; now; x = now, now = dad)
splay(now), rs = x, pushup(now);
}
#undef ls
#undef rs
#undef dad
}
int main(void)
{
using namespace LCT;
in(n); int foo, bar, typ, ans, bd = 3 * n + 1;
for (R int i = 1; i <= n; ++i)
{
deg[i] = 3;
for (R int j = 1; j <= 3; ++j) in(foo), tree[foo].fat = i;
}
deg[0] = 999;
for (R int i = n + 1; i <= bd; ++i) in(tree[i].val), tree[i].val <<= 1, q.push(i);
W (!q.empty())
{
foo = q.front(); q.pop();
tree[tree[foo].fat].val += tree[foo].val >> 1;
--deg[tree[foo].fat];
if (!deg[tree[foo].fat]) q.push(tree[foo].fat);
}
tree[0].val = 0, ans = tree[1].val >> 1;
in(m);
W (m--)
{
in(foo); typ = (tree[foo].val ^= 2) - 1;
foo = tree[foo].fat;
access(foo), splay(foo);
if (typ == 1)//0 -> 2
{
if (tree[foo].p1)
{
splay(foo = tree[foo].p1);
pushtag(tree[foo].son[1], 1);
pushup(tree[foo].son[1]);
tree[foo].val += typ;
pushup(foo);
}
else pushtag(foo, typ), pushup(foo), ans ^= 1;
}
else
{
if (tree[foo].p2)
{
splay(foo = tree[foo].p2);
pushtag(tree[foo].son[1], -1);
pushup(tree[foo].son[1]);
tree[foo].val += typ;
pushup(foo);
}
else pushtag(foo, typ), pushup(foo), ans ^= 1;
}
printf("%d\n", ans);
}
}