[Luogu P4332] [BZOJ 3553] [SHOI2014]三叉神經樹
洛谷傳送門
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 (