NOI2014 起牀困難綜合症 放在樹上,加上單點修改與鏈上查詢。c++
相似於原題,咱們只須要求出 \(0\) 和 \(2^{k - 1} - 1\) 走過這條鏈會變成什麼值,就能肯定每一位爲 \(0 / 1\) 走完後變成什麼值。ui
咱們對於 \(LCT\) 每一個節點維護兩個值 \(r_0,r_1\) 表示 \(0\) 和 \(2 ^ k - 1\) 從當前 \(LCT\) 維護的鏈底走到這個點會變成什麼值。spa
而後咱們就能夠把位運算操做變成一個值放在這個點上。debug
合併信息的時候,能夠這樣寫:code
inline Data operator + (const Data &lhs, const Data &rhs) { return (Data) { (~lhs.r0 & rhs.r0) | (lhs.r0 & rhs.r1), (~lhs.r1 & rhs.r0) | (rhs.r1 & lhs.r1) }; }
此處 \(\sim\) 是取反,也就是全部位反轉,注意此處須要用 unsigned long long
存,就沒有符號位,不會進行反轉。get
解釋前面那個地方 (~lhs.r0 & rhs.r0)
意味着最開始從 \(0\) 開始走,走完左子樹後仍是 \(0\) 而後繼續走 獲得的結果,it
(lhs.r0 & rhs.r1)
就是一開始從 \(0\) 走,走完左子樹後變成 \(1\) 而後繼續走 獲得的結果。io
另一個也是同理了,只是最開始從 \(1\) 走。class
可是這樣仍是不夠的,由於位運算是有順序的,\(reverse\) 的時候答案就會錯誤,因此咱們多存一個逆向的值就好了。bug
最後只須要像原題按位貪心就好了。
複雜度是 \(O(n + q (\log n + k))\) 的。
位運算時須要對全部位進行翻轉能夠用 \(\sim\) ,十分方便。
\(LCT\) 維護信息若是有順序的話,那麼須要維護一個逆向操做的答案才行。
具體能夠看看代碼實現(雖然寫的有點長。。)
#include <bits/stdc++.h> #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i) #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i) #define Set(a, v) memset(a, v, sizeof(a)) #define Cpy(a, b) memcpy(a, b, sizeof(a)) #define debug(x) cout << #x << ": " << (x) << endl #define DEBUG(...) fprintf(stderr, __VA_ARGS__) #define pb push_back using namespace std; typedef unsigned long long ull; template<typename T> inline bool chkmin(T &a, T b) {return b < a ? a = b, 1 : 0;} template<typename T> inline bool chkmax(T &a, T b) {return b > a ? a = b, 1 : 0;} namespace pb_ds { namespace io { const int MaxBuff = 1 << 22; const int Output = 1 << 24; char B[MaxBuff], *S = B, *T = B; #define getc() ((S == T) && (T = (S = B) + fread(B, 1, MaxBuff, stdin), S == T) ? 0 : *S++) char Out[Output], *iter = Out; inline void flush() { fwrite(Out, 1, iter - Out, stdout); iter = Out; } } template<class Type> inline Type read() { using namespace io; register char ch; register Type ans = 0; register bool neg = 0; while(ch = getc(), (ch < '0' || ch > '9') && ch != '-') ; ch == '-' ? neg = 1 : ans = ch - '0'; while(ch = getc(), '0' <= ch && ch <= '9') ans = ans * 10 + ch - '0'; return neg ? -ans : ans; } template<class Type> inline void Print(register Type x, register char ch = '\n') { using namespace io; if(!x) *iter++ = '0'; else { if(x < 0) *iter++ = '-', x = -x; static int s[100]; register int t = 0; while(x) s[++t] = x % 10, x /= 10; while(t) *iter++ = '0' + s[t--]; } *iter++ = ch; } } using namespace pb_ds; void File() { #ifdef zjp_shadow freopen ("P3613.in", "r", stdin); freopen ("P3613.out", "w", stdout); #endif } const int N = 1e5 + 1e3; #define ls(o) ch[o][0] #define rs(o) ch[o][1] struct Data { ull r0, r1; }; inline Data operator + (const Data &lhs, const Data &rhs) { return (Data) { (~lhs.r0 & rhs.r0) | (lhs.r0 & rhs.r1), (~lhs.r1 & rhs.r0) | (rhs.r1 & lhs.r1) }; } template<int Maxn> struct Link_Cut_Tree { int ch[Maxn][2], fa[Maxn]; Data fo[Maxn], fr[Maxn], val[Maxn]; inline bool is_root(int o) { return ls(fa[o]) != o && rs(fa[o]) != o; } inline bool get(int o) { return rs(fa[o]) == o; } inline void push_up(int o) { fo[o] = fr[o] = val[o]; if (ls(o)) fo[o] = fo[ls(o)] + fo[o], fr[o] = fr[o] + fr[ls(o)]; if (rs(o)) fo[o] = fo[o] + fo[rs(o)], fr[o] = fr[rs(o)] + fr[o]; } inline void rotate(int v) { int u = fa[v], t = fa[u], d = get(v); fa[ch[u][d] = ch[v][d ^ 1]] = u; fa[v] = t; if (!is_root(u)) ch[t][rs(t) == u] = v; fa[ch[v][d ^ 1] = u] = v; push_up(v); push_up(u); } bool rev[Maxn]; inline void Get_Rev(int o) { rev[o] ^= 1; swap(ls(o), rs(o)); swap(fo[o], fr[o]); } inline void push_down(int o) { if (rev[o]) Get_Rev(ls(o)), Get_Rev(rs(o)), rev[o] = false; } void Push_All(int o) { if (!is_root(o)) Push_All(fa[o]); push_down(o); } inline void Splay(int o) { Push_All(o); for (; !is_root(o); rotate(o)) if (!is_root(fa[o])) rotate(get(o) != get(fa[o]) ? o : fa[o]); push_up(o); } inline void Access(int o) { for (int t = 0; o; o = fa[t = o]) Splay(o), rs(o) = t, push_up(o); } inline void Make_Root(int o) { Access(o); Splay(o); Get_Rev(o); } inline void Split(int u, int v) { Make_Root(u); Access(v); Splay(v); } }; Link_Cut_Tree<N> T; vector<int> G[N]; void Build(int u = 1, int fa = 0) { T.fa[u] = fa; for (int v : G[u]) if (v != fa) Build(v, u); } int main () { File(); int n = read<int>(), m = read<int>(), k = read<int>(); For (i, 1, n) { int x = i, y = read<int>(); ull z = read<ull>(); if (y == 1) T.val[x].r0 = 0ull, T.val[x].r1 = z; if (y == 2) T.val[x].r0 = z, T.val[x].r1 = ~0ull; if (y == 3) T.val[x].r0 = z, T.val[x].r1 = ~z; T.push_up(x); } For (i, 1, n - 1) { int u = read<int>(), v = read<int>(); G[u].pb(v); G[v].pb(u); } Build(); For (i, 1, m) { int opt = read<int>(), x = read<int>(), y = read<int>(); ull z = read<ull>(); if (opt == 1) { T.Split(x, y); ull val0 = T.fo[y].r0, val1 = T.fo[y].r1, res = 0, cur = 0; for (ull i = 1ull << (k - 1); i; i >>= 1) { if ((val0 & i) < (val1 & i) && cur + i <= z) cur += i, res += val1 & i; else res += val0 & i; } Print(res); } else { T.Access(x); T.Splay(x); if (y == 1) T.val[x].r0 = 0ull, T.val[x].r1 = z; if (y == 2) T.val[x].r0 = z, T.val[x].r1 = ~0ull; if (y == 3) T.val[x].r0 = z, T.val[x].r1 = ~z; T.push_up(x); } } io :: flush(); return 0; }