[Luogu P4332] [BZOJ 3553] [SHOI2014]三叉神经树

版权声明:欢迎转载蒟蒻博客,但请注明出处: https://blog.csdn.net/LPA20020220/article/details/85370236

洛谷传送门

BZOJ传送门

题目描述

计算神经学作为新兴的交叉学科近些年来一直是学术界的热点。一种叫做SHOI 的神经组织因为其和近日发现的化合物 SHTSC 的密切联系引起了人们的极大关注。

SHOI 组织由若干个 SHOI 细胞构成,SHOI 细胞之间形成严密的树形结构。每个 SHOI 细胞都有且只有一个输出端,被称为轴突,除了一个特殊的、被称为根细胞的 SHOI 细胞的输出作为整个组织的输出以外,其余细胞的轴突均连向其上级 SHOI 细胞;并且有且只有三个接收端,被称为树突,从其下级细胞或者其它神经组织那里接收信息。SHOI 细胞的信号机制较为简单,仅有 0 0 1 1 两种。每个 SHOI 细胞根据三个输入端中 0 0 1 1 信号的多寡输出较多的那一种。

现在给出了一段 SHOI 组织的信息,以及外部神经组织的输入变化情况。请你模拟 SHOI 组织的输出结果。

输入输出格式

输入格式:

输入的第一行包含一个整数 n n 。表示 SHOI 组织的总细胞个数。SHOI 细胞由 1 n 1\sim n 编号,编号为 1 1 的是根细胞。

从第二行开始的 n n 行,每行三个整数 x 1 , x 2 , x 3 x_1, x_2, x_3 ,分别表示编号为 1 n 1\sim n 的 SHOI 细胞的树突连接。 1 < x i n 1 < x_i \leq n 表示连向编号为 x i x_i 的细胞的轴突, n < x i 3 n + 1 n < x_i \leq 3n+1 表示连向编号为 x i x_i 的外界输入。输入数据保证给出的 SHOI 组织是合法的,且所有的 x i x_i 两两不同。

接下来一行包含 2 n + 1 2n+1 0 / 1 0/1 的整数,表示初始时的外界输入。

n + 3 n+3 行有一个整数 q q ,表示总操作数。

之后 q q 行每行一个整数 x x ,表示编号为 x x 的外界输入发生了变化。

输出格式:

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

输入输出样例

输入样例#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

说明

对于 10 % 10 \% 的数据, n 1000 , q 1000 n \leq 1000, q \leq 1000

对于 30 % 30 \% 的数据, n 100000 , q 100000 n \leq 100000, q \leq 100000

对于 100 % 100 \% 的数据, n 500000 , q 500000 n \leq 500000, q \leq 500000

解题分析

可以发现, 每次更改最底层的结果会改变自底向上的一条链上连续 0 / 1 0/1 的结果, 更具体地说, 设 v a l [ i ] val[i] i i 号节点的权值, 那么改变的是自底部开始的 v a l = 1 / 2 val=1/2 的一部分。

那么我们直接用 L C T LCT 维护链上从下向上第一个权值不为 1 / 2 1/2 的位置, 在修改的时候直接 a c c e s s access 后找到这个位置, 再区间打一个修改 t a g tag 就好了。

注意如果到根节点都没有要求的点, 直接修改答案, 在根节点上打 t a g tag

代码如下:

#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);
	}
}

猜你喜欢

转载自blog.csdn.net/LPA20020220/article/details/85370236
今日推荐