Solution -「LOCAL」Burning Flowers
阿新 • • 發佈:2020-08-24
灼之花好評,條條生日快樂(假裝現在 8.15)!
\(\mathcal{Description}\)
給定一棵以 \(1\) 為根的樹,第 \(i\) 個結點有顏色 \(c_i\) 和光亮值 \(l_i\),定義樹的權值為:
\[\sum_{\displaystyle u<v\land c_u=c_v\land\\\operatorname{LCA}(u,v)\not=u\land\operatorname{LCA}(u,v)\not=v}l_u\oplus l_v \]
現有 \(m\) 次修改,每次修改某點的顏色或光亮值,求出每次修改後樹的權值。
\(n,m\le10^5\)
\(\mathcal{Solution}\)
分顏色貢獻,位運算拆位,基本姿勢 w!
假定樹的結點全部同色且光亮值為 \(0/1\),考慮點 \(u\) 的貢獻,顯然先加上所有能與它異或成 \(1\) 的結點個數,再減去在子樹內或在祖先上的結點個數。而從動態修改的角度,兩者都能使用 BIT(樹狀陣列)維護!
所以,列舉每個顏色 \(c\),對於每一個 bit,維護兩個 BIT,分別儲存子樹內顏色為 \(c\) 且當前 bit 為 \(1\) 的結點個數和祖先上顏色為 \(c\) 且當前 bit 為 \(1\) 的結點個數,處理修改就暴力除去貢獻再更新貢獻即可。
複雜度 \(\mathcal O(20(n+m)\log n)\)。
\(\mathcal{Code}\)
#include <cstdio> #include <vector> #include <iostream> typedef long long LL; inline char fgc () { static char buf[1 << 17], *p = buf, *q = buf; return p == q && ( q = buf + fread ( p = buf, 1, 1 << 17, stdin ), p == q ) ? EOF : *p ++; } inline int rint () { int x = 0; char s = fgc (); for ( ; s < '0' || '9' < s; s = fgc () ); for ( ; '0' <= s && s <= '9'; s = fgc () ) x = x * 10 + ( s ^ '0' ); return x; } inline void wint ( const LL x ) { if ( 9 < x ) wint ( x / 10 ); putchar ( x % 10 ^ '0' ); } const int MAXN = 1e5; int n, m, ecnt, head[MAXN + 5], col[MAXN + 5], val[MAXN + 5]; int dfc, dep[MAXN + 5], dfn[MAXN + 5], siz[MAXN + 5]; LL ans[MAXN + 5]; struct Edge { int to, nxt; } graph[MAXN * 2 + 5]; struct BinaryIndexTree { int val[MAXN + 5]; inline int lowbit ( const int x ) { return x & -x; } inline void update ( int x, const int k ) { for ( ; x <= n; x += lowbit ( x ) ) val[x] += k; } inline int sum ( int x ) { int ret = 0; for ( ; x; x -= lowbit ( x ) ) ret += val[x]; return ret; } inline int sum ( const int l, const int r ) { return sum ( r ) - sum ( l - 1 ); } } facnt, soncnt, fabit[20], sonbit[20]; struct BitBucket { int all, cnt[20]; inline void clear () { all = 0; for ( int i = 0; i < 20; ++ i ) cnt[i] = 0; } inline void update ( const int x, const int k ) { all += k; for ( int i = 0; 1 << i <= x; ++ i ) { if ( ( x >> i ) & 1 ) { cnt[i] += k; } } } inline LL query ( const int x ) { LL ret = 0; for ( int i = 0; i < 20; ++ i ) { if ( ( x >> i ) & 1 ) ret += 1ll * ( all - cnt[i] ) << i; else ret += 1ll * cnt[i] << i; } return ret; } } buc; struct Event { int u, val, time, type; Event () {} Event ( const int tu, const int tv, const int tti, const int tty ): u ( tu ), val ( tv ), time ( tti ), type ( tty ) {} }; std::vector<Event> evt[MAXN + 5]; inline void link ( const int s, const int t ) { graph[++ ecnt].to = t, graph[ecnt].nxt = head[s]; head[s] = ecnt; } inline void init ( const int u, const int f ) { siz[u] = 1, dfn[u] = ++ dfc, dep[u] = dep[f] + 1; for ( int i = head[u], v; i; i = graph[i].nxt ) { if ( ( v = graph[i].to ) ^ f ) { init ( v, u ), siz[u] += siz[v]; } } } inline void initEvent () { m = rint (); for ( int i = 1; i <= n; ++ i ) evt[col[i]].push_back ( Event ( i, val[i], 0, 1 ) ); for ( int i = 1, op, u, t; i <= m; ++ i ) { op = rint (), u = rint (), t = rint (); evt[col[u]].push_back ( Event ( u, val[u], i, 0 ) ); if ( op & 1 ) evt[col[u] = t].push_back ( Event ( u, val[u], i, 1 ) ); else evt[col[u]].push_back ( Event ( u, val[u] = t, i, 1 ) ); } for ( int i = 1; i <= n; ++ i ) evt[col[i]].push_back ( Event ( i, val[i], m + 1, 0 ) ); } inline LL queryFa ( const int u, const int val ) { LL ret = 0; int all = facnt.sum ( dfn[u] ); for ( int i = 0; i < 20; ++ i ) { if ( ( val >> i ) & 1 ) ret += 1ll * ( all - fabit[i].sum ( dfn[u] ) ) << i; else ret += 1ll * fabit[i].sum ( dfn[u] ) << i; } return ret; } inline void updateFa ( const int u, const int val, const int k ) { int l = dfn[u], r = dfn[u] + siz[u]; facnt.update ( l, k ), facnt.update ( r, -k ); for ( int i = 0; 1 << i <= val; ++ i ) { if ( ( val >> i ) & 1 ) { fabit[i].update ( l, k ); fabit[i].update ( r, -k ); } } } inline LL querySon ( const int u, const int val ) { LL ret = 0; int l = dfn[u], r = dfn[u] + siz[u] - 1; int all = soncnt.sum ( l, r ); for ( int i = 0; i < 20; ++ i ) { if ( ( val >> i ) & 1 ) ret += 1ll * ( all - sonbit[i].sum ( l, r ) ) << i; else ret += 1ll * sonbit[i].sum ( l, r ) << i; } return ret; } inline void updateSon ( const int u, const int val, const int k ) { soncnt.update ( dfn[u], k ); for ( int i = 0; 1 << i <= val; ++ i ) { if ( ( val >> i ) & 1 ) { sonbit[i].update ( dfn[u], k ); } } } int main () { freopen ( "cop.in", "r", stdin ); freopen ( "cop.out", "w", stdout ); n = rint (); for ( int i = 1; i <= n; ++ i ) col[i] = rint (); for ( int i = 1; i <= n; ++ i ) val[i] = rint (); for ( int i = 1, u, v; i < n; ++ i ) { u = rint (), v = rint (); link ( u, v ), link ( v, u ); } init ( 1, 0 ), initEvent (); for ( int c = 1; c <= n; ++ c ) { buc.clear (); LL sum = 0, ill = 0; for ( int i = 0; i ^ evt[c].size (); ++ i ) { Event cur ( evt[c][i] ); if ( cur.type ) { sum += buc.query ( cur.val ), buc.update ( cur.val, 1 ); ill += queryFa ( cur.u, cur.val ), updateFa ( cur.u, cur.val, 1 ); ill += querySon ( cur.u, cur.val ); updateSon ( cur.u, cur.val, 1 ); } else { sum -= buc.query ( cur.val ), buc.update ( cur.val, -1 ); ill -= queryFa ( cur.u, cur.val ), updateFa ( cur.u, cur.val, -1 ); ill -= querySon ( cur.u, cur.val ), updateSon ( cur.u, cur.val, -1 ); } if ( cur.time <= m ) { ans[cur.time] += sum - ill; ans[i + 1 == ( int ) evt[c].size () ? m + 1 : evt[c][i + 1].time] -= sum - ill; } } } wint ( ans[0] ), putchar ( '\n' ); for ( int i = 1; i <= m; ++ i ) printf ( "%lld", ans[i] += ans[i - 1] ), putchar ( '\n' ); return 0; }
\(\mathcal{Details}\)
考場上卡常 \(\mathcal O(n(m+\log n))\) 騙到 \(50pts\) 心滿意足 www。
這種類似離線的處理方法要感知到位,畢竟兔子這種碼力持久化啊虛樹啊都不可能考場敲出來 qwq(自暴自棄。