[LCT]P4332三叉神經樹
阿新 • • 發佈:2019-02-26
define 一段 val va_arg push freopen clas 1的個數 討論 的時候,就成了找從根到 \(x\)的路徑上最深的,val不為1的點 \(y\) ,再將 \(y\) 與 \(x\) 拉出一條鏈,區間修改這顆從 \(x\) 到 \(y\) 的 \(Splay (\)每個點的權值 \(+1)\) , 詢問就 \(splay(1)\) ,討論下 \(val[1]\)
題面
\(Solution\)
通過模擬,我們會發現每次修改 \(x\),只會改變從 \(x\) 向上一段連續的鏈的輸出。
例如將 \(x\) 點從 \(0\) 改為 \(1,\) 那麽它會影響從它向上的一段連續的鏈,這條鏈上的每一個節點的 \(1\) 兒子的個數為 \(1(\) 原來都輸出 \(0\) ,改完後輸出 \(1)\)
\(x\) 從 \(1\) 變 \(0\) 同理
所以我們只需要知道這條鏈,然後就可以樹剖/\(LCT\)去維護。
這裏給出 \(LCT\) 解法
記 \(val[x]\) 為 \(x\) 的兒子中 \(1\) 的個數,
那麽當修改一個點 \(x\) 從 \(0\) 變 \(1\)
\(x\) 從 \(1\) 變 \(0\) 同理
\(Source\)
#include <stdio.h> #include <assert.h> #include <ctype.h> #include <set> #include <cstring> using namespace std; namespace io { char buf[1<<21], *pos = buf, *end = buf; inline char getc() { return pos == end && (end = (pos = buf) + fread(buf, 1, 1<<21, stdin), pos == end) ? EOF : *pos ++; } inline int rint() { register int x = 0, f = 1; register char c; while (!isdigit(c = getc())) if (c == '-') f = -1; while (x = (x << 1) + (x << 3) + (c ^ 48), isdigit(c = getc())); return x * f; } template<typename T> inline bool chkmin(T &x, T y) { return x > y ? (x = y, 0) : 1; } template<typename T> inline bool chkmax(T &x, T y) { return x < y ? (x = y, 0) : 1; } #define debug(...) fprintf(stderr, __VA_ARGS__) #define rep(i, a, b) for (register int i = a; i <= b; ++ i) #define dep(i, a, b) for (register int i = a; i >= b; -- i) #define travel(i, u) for (register int i = head[u]; i; i = nxt[i]) #define mem(a, b) memset(a, b, sizeof a) } using io::rint; const int N = 1.5e6 + 5;//開三倍,題目要求 int ch[N][3], n, q, fa[N]; struct LCT { #define ls(x) (ch[x][0]) #define rs(x) (ch[x][1]) #define chk(x) (ch[fa[x]][1] == x) int ch[N][2], val[N], tag[N], fa[N]; bool not1[N], not2[N];//notx[u]表示以u為根的子樹中是否有權值不為x的點,沒有為0, 有為1 bool isroot(int x) { return ls(fa[x]) ^ x && rs(fa[x]) ^ x; } void add(int x, int z) { val[x] += z; tag[x] += z; if (z > 0) not2[x] = not1[x], not1[x] = 0; else not1[x] = not2[x], not2[x] = 0; } void pushup(int x) { not1[x] = not1[ls(x)] | not1[rs(x)] | (val[x] != 1); not2[x] = not2[ls(x)] | not2[rs(x)] | (val[x] != 2); } void pushdown(int x) { if (!tag[x]) return; if (ls(x)) add(ls(x), tag[x]); if (rs(x)) add(rs(x), tag[x]); tag[x] = 0; } void rotate(int x) { int y = fa[x], z = fa[y], k = chk(x), tmp = ch[x][k ^ 1]; ch[y][k] = tmp, fa[tmp] = y; if (!isroot(y)) ch[z][chk(y)] = x; fa[x] = z; ch[x][k ^ 1] = y, fa[y] = x; pushup(y), pushup(x); } int stk[N], top; void splay(int x) { stk[top = 1] = x; for (int i = x; !isroot(i); i = fa[i]) stk[++top] = fa[i]; while (top) pushdown(stk[top--]); while (!isroot(x)) { int y = fa[x], z = fa[y]; if (!isroot(y)) if (chk(x) == chk(y)) rotate(y); else rotate(x); rotate(x); } } void access(int x) { for (int y = 0; x; x = fa[y = x]) splay(x), rs(x) = y, pushup(x); } int findnot1(int x) { pushdown(x); if (!not1[x]) return 0; if (not1[rs(x)]) return findnot1(rs(x)); if (val[x] != 1) return x; return findnot1(ls(x)); } int findnot2(int x) { pushdown(x); if (!not2[x]) return 0; if (not2[rs(x)]) return findnot2(rs(x)); if (val[x] != 2) return x; return findnot2(ls(x)); } } T; void DFS(int x) { if (x <= n) { rep (i, 0, 2) { DFS(ch[x][i]); T.val[x] += (T.val[ch[x][i]] >> 1);//預處理出每個點的權值 } } } int main() { #ifndef ONLINE_JUDGE freopen("P4332.in", "r", stdin); freopen("P4332.out", "w", stdout); #endif n = rint(); rep (i, 1, n) rep (j, 0, 2) { ch[i][j] = rint(); fa[ch[i][j]] = T.fa[ch[i][j]] = i; } rep (i, n + 1, 3 * n + 1) { T.val[i] = rint(); T.val[i] ++;//很巧妙地計算權值,val存的是兒子中1的個數 } DFS(1); q = rint(); while (q --) { int x = rint(); T.access(x); T.splay(x); if (T.val[x] > 1) {//1 - > 0 說明只有2的鏈才會改變 int y = T.findnot2(T.ch[x][0]); T.access(fa[y]); T.splay(x); T.add(x, -1); } else {// 0 -> 1 說明只有1的鏈會改變 int y = T.findnot1(T.ch[x][0]); T.access(fa[y]); T.splay(x); T.add(x, 1); } T.splay(1); printf("%d\n", T.val[1] > 1); } }
[LCT]P4332三叉神經樹