题意
- 给你一颗满三叉树,每个点权值定义为所有子节点权值和,叶子节点有一个属于的权值,每次修改一个叶子节点的权值,在修改后回答根节点的权值()。
首先感谢Hany01的讲解,我们首先观察一下性质,发现每次修改只会修改修改点到根节点路径的一端前缀,而且这连续一端的位置权值是相同的,那么我们要找到这个前缀的末尾,也就是第一个和前一段权值不同的位置,我们可以用LCT来维护这棵三叉树,辅助树中每个点保存一个点的子树内是否有权值非和非的点,那么我们修改就很好做了。
首先把修改点Access后Splay到根上,那么除了它之外它到根路径上的所有点都会在它的左子树,我们只需要在Splay上二分查找深度最大的位置即可,找到这个位置之后我们把这个点在原树中的父亲Access,也就相当于断了它和它子节点之间的联系,那么我们最后Splay修改点,在上面打标记就好了,复杂度,常数似乎还过得去,平均每个点跑了毫秒。
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define mp make_pair
#define inf (0x3f3f3f3f)
#define mem(a, b) memset(a, b, sizeof(a))
#define Rep(i, a) for (int i = 0; i < a; ++ i)
#define For(i, a, b) for (int i = a; i <= b; ++ i)
#define Forr(i, a, b) for (int i = a; i >= b; -- i)
#define Travel(i, x) for (int i = head[x]; i; i = nxt[i])
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
template<class T>inline T read(T &_) {
T __ = getchar(), ___ = 1; _ = 0;
for (; !isdigit(__); __ = getchar()) if (__ == '-') ___ = -1;
for (; isdigit(__); __ = getchar()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
return _ *= ___;
}
template<class T>inline bool chkmax(T &_, T __) { return _ < __ ? _ = __, 1 : 0; }
template<class T>inline bool chkmin(T &_, T __) { return _ > __ ? _ = __, 1 : 0; }
inline void proStatus() {
ifstream t("/proc/self/status");
cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>());
}
const int N = 1.5e6 + 7;
int ch[N][3], fa[N], n, q;
struct Link_Cut_Tree {
#define ls(x) (ch[x][0])
#define rs(x) (ch[x][1])
#define rel(x) (x == rs(fa[x]))
int ch[N][2], fa[N];
int Sta[N], a[N], top;
int not1[N], not2[N], tag[N];
bool isroot(int x) { return ls(fa[x]) ^ x && rs(fa[x]) ^ x; }
void add(int x, int z) {
tag[x] += z, a[x] += z;
if (z > 0) not2[x] = not1[x], not1[x] = 0;
else not1[x] = not2[x], not2[x] = 0;
}
void pushdown(int x) {
if (tag[x]) {
if (ls(x)) add(ls(x), tag[x]);
if (rs(x)) add(rs(x), tag[x]);
tag[x] = 0;
}
}
void pushup(int x) {
not1[x] = not1[ls(x)] | not1[rs(x)] | (a[x] != 1);
not2[x] = not2[ls(x)] | not2[rs(x)] | (a[x] != 2);
}
void rotate(int x) {
int dad = fa[x], f = rel(x);
if (!isroot(dad)) ch[fa[dad]][rel(dad)] = x;
fa[x] = fa[dad], ch[dad][f] = ch[x][f ^ 1];
fa[ch[x][f ^ 1]] = dad, fa[dad] = x, ch[x][f ^ 1] = dad;
pushup(dad), pushup(x);
}
void splay(int x) {
Sta[top = 1] = x;
for (int i = x; !isroot(i); i = fa[i])
Sta[++ top] = fa[i];
while (top) pushdown(Sta[top --]);
for (; !isroot(x); rotate(x))
if (!isroot(fa[x]))
rotate(rel(x) ^ rel(fa[x]) ? x : fa[x]);
}
void access(int x) {
for (int y = 0; x; x = fa[y = x])
splay(x), rs(x) = y, pushup(x);
}
int find1(int x) {
pushdown(x);
if (!not1[x]) return 0;
if (not1[rs(x)]) return find1(rs(x));
if (a[x] != 1) return x;
return find1(ls(x));
}
int find2(int x) {
pushdown(x);
if (!not2[x]) return 0;
if (not2[rs(x)]) return find2(rs(x));
if (a[x] != 2) return x;
return find2(ls(x));
}
} T;
void dfs(int x) { if (x <= n) Rep(j, 3) dfs(ch[x][j]), T.a[x] += T.a[ch[x][j]] >> 1; }
int main() {
//freopen("2187.in", "r", stdin);
//freopen("2187.out", "w", stdout);
read(n);
For(i, 1, n) Rep(j, 3) {
read(ch[i][j]);
fa[ch[i][j]] = T.fa[ch[i][j]] = i;
}
For(i, n + 1, n * 3 + 1)
read(T.a[i]), ++ T.a[i];
dfs(1);
for (int x = read(q), y; q -- ;) {
read(x), T.access(x), T.splay(x);
if (T.a[x] > 1) {
y = T.find2(T.ch[x][0]);
T.access(fa[y]);
T.splay(x), T.add(x, -1);
} else {
y = T.find1(T.ch[x][0]);
T.access(fa[y]);
T.splay(x), T.add(x, 1);
}
T.splay(1);
//cout << T.a[1] << endl;
printf("%d\n", T.a[1] > 1);
}
return 0;
}