日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[BZOJ3730]震波

發布時間:2024/1/18 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [BZOJ3730]震波 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目

??點這里看題目。
?? BZOJ 目測…是炸了。

分析

??動態點分治入門題。
??首先理解什么叫 " 動態點分治 "。
??一般點分治需要離線解決,不帶修改。動態點分治可以用點分治的方法在線解決問題,支持修改。
??在點分治的過程中,每個點都會成為一次分治中心進行計算。如果我們將點按照計算順序連成一棵樹的話,我們就會得到原樹的一顆 " 虛樹 " , 我們稱之為點分樹。煮個栗子:

??可以發現,由于重心的先天性質,點分樹的樹高為 O ( log ? 2 n ) O(\log_2n) O(log2?n)
??對于本題,由于只會有單點修改(例如修改 u u u),所以我們可以在點分樹上從 u u u開始,對于 u u u到點分樹的根的路徑進行暴力修改,這樣只會有 O ( log ? 2 n ) O(\log_2n) O(log2?n)個點。再深的點不會受到影響(因為對于更深的點,它們進行點分治的時候, u u u已經沒有了)。
??如何維護信息?我們對于點分樹上每一個點 u u u維護兩個樹狀數組,第一個樹狀數組維護下標為到 u u u距離的權值和,用于直接計算貢獻;第二個樹狀數組維護下標為到 u u u點分樹上父親距離的權值和,用于容斥扣除重復貢獻。統計的方式類似于修改,我們在點分樹上從 u u u開始上跳,用樹狀數組計算貢獻。再煮個栗子:

??現在想必各位都懂了。
??需要注意的幾點:
??1. 注意點分樹上,祖先到自己的距離并不是單調遞增的。因此不能中途 break。
??2. 由于我們只需要知道點分樹上祖先到自己的距離和祖先的標號,且點分樹深度有限,因此我們把這兩個值用數組存下來即可。
??3. 樹狀數組需要用 vector 存。僅存下需要的空間會優化到 O ( n log ? 2 n ) O(n\log_2n) O(nlog2?n)(跟點分治基礎時間復雜度一樣),而不優化會變成 O ( n 2 ) O(n^2) O(n2), MLE。
??4. 樹狀數組注意下標不要變成非正數。
??5. 函數千萬千萬不要傳 vector 的值!!!親測會慢 10 倍!!!

代碼

#include <map> #include <cmath> #include <vector> #include <cstdio> #include <cstring> using namespace std;const int MAXN = 1e5 + 5, MAXLOG = 20;template<typename _T> void read( _T &x ) {x = 0;char s = getchar();int f = 1;while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}x *= f; }template<typename _T> void write( _T x ) {if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }if( 9 < x ){ write( x / 10 ); }putchar( x % 10 + '0' ); }template<typename _T> _T MAX( const _T a, const _T b ) {return a > b ? a : b; }template<typename _T> _T MIN( const _T a, const _T b ) {return a < b ? a : b; }struct edge {int to, nxt; }Graph[MAXN << 1];vector<int> BIT[MAXN][2]; int f[MAXN][MAXLOG], dis[MAXN][MAXLOG]; int siz[MAXN], dep[MAXN], mx[MAXN]; int head[MAXN], curVal[MAXN], val[MAXN]; int N, M, all, cnt; bool vis[MAXN];int lowbit( const int &x ) { return x & ( -x ); } void upt( int &x, const int v ) { x = MAX( x, v ); } bool visible( const int u, const int fa ) { return u ^ fa && ! vis[u]; }void update( const int u, const int t, int x, const int v ) {int lim = BIT[u][t].size() - 1;for( ; x <= lim && x ; x += lowbit( x ) ) BIT[u][t][x] += v; }int getSum( const int u, const int t, int x ) {x = MIN( x, ( int ) BIT[u][t].size() - 1 ); int ret = 0;for( ; x > 0 ; x -= lowbit( x ) ) ret += BIT[u][t][x];return ret; }void addEdge( const int from, const int to ) {Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];head[from] = cnt; }int getCen( const int u, const int fa ) {int ret = 0, tmp; siz[u] = 1, mx[u] = 0;for( int i = head[u], v ; i ; i = Graph[i].nxt )if( visible( v = Graph[i].to, fa ) ){tmp = getCen( v, u );siz[u] += siz[v], mx[u] = MAX( mx[u], siz[v] );if( mx[tmp] < mx[ret] ) ret = tmp;}mx[u] = MAX( mx[u], all - siz[u] );if( mx[u] < mx[ret] ) ret = u;return ret; }void DFS( const int u, const int fa, const int rt, const int d ) {for( int i = head[u], v ; i ; i = Graph[i].nxt )if( visible( v = Graph[i].to, fa ) )dis[v][++ dep[v]] = d, f[v][dep[v]] = rt,DFS( v, u, rt, d + 1 ); }void divide( const int u ) {vis[u] = true; DFS( u, 0, u, 1 );int tmp = all;BIT[u][0].resize( tmp + 1 ), BIT[u][1].resize( tmp + 1 );for( int i = head[u], v ; i ; i = Graph[i].nxt )if( ! vis[v = Graph[i].to] ){all = siz[v]; if( all > siz[u] ) all = tmp - siz[u];divide( getCen( v, u ) );} }void change( const int u, const int nVal ) {int dif = nVal - curVal[u]; curVal[u] = nVal;update( u, 1, dis[u][dep[u]], dif );for( int i = dep[u] ; i ; i -- )update( f[u][i], 0, dis[u][i], dif ),update( f[u][i], 1, dis[u][i - 1], dif ); }int query( const int u, const int k ) {int ret = getSum( u, 0, k ) + curVal[u];for( int i = dep[u] ; i ; i -- )if( dis[u][i] <= k ){ret += getSum( f[u][i], 0, k - dis[u][i] ) + curVal[f[u][i]];ret -= getSum( f[u][i + 1], 1, k - dis[u][i] );}return ret; }int main() {read( N ), read( M );for( int i = 1 ; i <= N ; i ++ ) read( val[i] );for( int i = 1, a, b ; i < N ; i ++ ) read( a ), read( b ), addEdge( a, b ), addEdge( b, a );mx[0] = all = N; divide( getCen( 1, 0 ) );for( int i = 1 ; i <= N ; i ++ ) f[i][dep[i] + 1] = i;for( int i = 1 ; i <= N ; i ++ ) change( i, val[i] );int op, a, b, lst = 0;while( M -- ){read( op ), read( a ), read( b );a ^= lst, b ^= lst;if( op ) change( a, b );else write( lst = query( a, b ) ), putchar( '\n' );}return 0; }

總結

以上是生活随笔為你收集整理的[BZOJ3730]震波的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。