CF1491H Yuezheng Ling and Dynamic Tree(分块)
CF1491H Yuezheng Ling and Dynamic Tree
- description
- solution
- code
description
題目鏈接
solution
非常清新的小分塊題了
前提:將序列分成n\sqrt{n}n?塊,每塊有n\sqrt{n}n?個數(shù),記第iii個塊的左右邊界為Li,RiL_i,R_iLi?,Ri?,記第iii個數(shù)所在塊為blockiblock_iblocki?
定義topitop_itopi?:節(jié)點iii的祖先中,與iii不在同一個塊的最大編號點
【這個真的很妙,可以說是這道題的解法考察點了】
問題是如何在al,ra_{l,r}al,r?更新時,對某個塊xxx內(nèi)的被覆蓋節(jié)點i∈[l,r]i\in[l,r]i∈[l,r]的topitop_itopi?進行更新??
- 如果更新后的ai<Lxa_i<L_xai?<Lx?,則aia_iai?成為新的滿足toptoptop定義的最大編號點【iii的祖先都已經(jīng)全變成了aia_iai?的祖先,再加個aia_iai?本身】,topi=aitop_i=a_itopi?=ai?
- 如果更新后的aia_iai?仍然屬于塊xxx內(nèi),則直接鏈接過去,topi=topaitop_i=top_{a_i}topi?=topai??
明白了如何維護塊內(nèi)信息,接下來就是對不同塊進行操作了
首先考慮修改操作
-
散塊(只覆蓋了塊內(nèi)部分點):直接暴力修改點的aia_iai?值,然后暴力重構(gòu),單次操作時間復(fù)雜度O(n)O(\sqrt{n})O(n?)
-
整塊:懶標(biāo)記tagitag_itagi?表示點iii的aia_iai?還沒減多少【比真實的aia_iai?多了tagitag_itagi?,未真實操作修改】,但這個時候塊內(nèi)某些點的topitop_itopi?可能已經(jīng)發(fā)生了變化,沒有實時更新就會影響后面的查詢操作,而每次暴力修改又需要整個塊的遍歷,多個整塊幾乎就是O(O(O(修改區(qū)間長度)))的,無法保證時間復(fù)雜度
實際上,發(fā)現(xiàn)對于每個塊,經(jīng)過n\sqrt{n}n?次整塊修改操作后,aia_iai?都至少會變?yōu)?span id="ze8trgl8bvbq" class="katex--inline">ai?na_i-\sqrt{n}ai??n?,一定在當(dāng)前塊前面的塊
因此,我們可以維護每個塊被修改的次數(shù)cntxcnt_xcntx?當(dāng)cntx>ncnt_x>\sqrt{n}cntx?>n?,就不再暴力修改整塊,而是直接整塊的區(qū)間減法,這個時候的aia_iai?一定是其的topitop_itopi?,否則就暴力修改
每個塊最多修改n\sqrt{n}n?次,每次需要O(n)O(\sqrt{n})O(n?)遍歷修改,一共有n\sqrt{n}n?個塊,總時間復(fù)雜度是O(nn)O(n\sqrt{n})O(nn?)的
接著考慮詢問操作
找lca\text{lca}lca肯定是倍增暴力啦!這里直接使用暴力爬山法
考慮詢問u,vu,vu,v兩個點的lcalcalca
-
若blocku≠blockvblock_u\neq block_vblocku??=blockv?,則選擇對應(yīng)blockblockblock編號較大的點,跳到其toptoptop點
-
若blocku=blockvblock_u=block_vblocku?=blockv?且topu≠topvtop_u\neq top_vtopu??=topv?,則兩個節(jié)點一起跳對應(yīng)的toptoptop點
-
若blocku=blockvblock_u=block_vblocku?=blockv?且topu=topvtop_u=top_vtopu?=topv?,則一直讓節(jié)點編號大的點跳父親aaa,直到兩點相同為止
【注意在跳的時候,一定要減去所在塊的tagxtag_xtagx?標(biāo)記,才能得到真正的top/atop/atop/a】
一個點跳toptoptop的次數(shù)最多為nn=n\frac{n}{\sqrt{n}}=\sqrt{n}n?n?=n?次,跳完toptoptop就是在一個塊里面的跳aaa,最多也是n\sqrt{n}n?次,所以單次詢問時間復(fù)雜度為O(n)O(\sqrt{n})O(n?)
本題最終的時間復(fù)雜度為O((n+q)n)O((n+q)\sqrt{n})O((n+q)n?)
code
#include <cmath> #include <cstdio> #include <iostream> using namespace std; #define maxn 100005 #define maxB 320 int n, Q, B, B_cnt; int a[maxn], block[maxn], L[maxB], R[maxB], cnt[maxB], top[maxn], tag[maxB];void pushup( int x ) {for( int i = L[x];i <= R[x];i ++ ) a[i] = max( 1, a[i] - tag[x] );tag[x] = 0;for( int i = L[x];i <= R[x];i ++ ) {if( a[i] < L[x] ) top[i] = a[i];else top[i] = top[a[i]];} }void modify( int l, int r, int x ) {if( block[l] == block[r] ) {for( int i = l;i <= r;i ++ ) a[i] = max( 1, a[i] - x );pushup( block[l] );}else {for( int i = l;i <= R[block[l]];i ++ ) a[i] = max( 1, a[i] - x ); pushup( block[l] );for( int i = L[block[r]];i <= r;i ++ ) a[i] = max( 1, a[i] - x ); pushup( block[r] );for( int i = block[l] + 1;i < block[r];i ++ ) {cnt[i] ++, tag[i] = min( n, tag[i] + x );if( cnt[i] <= B ) pushup( i );}} }int query_top( int i ) { return max( 1, top[i] - tag[block[i]] ); }int query_a( int i ) { return max( 1, a[i] - tag[block[i]] ); }int lca( int x, int y ) {while( 1 ) {if( block[x] < block[y] ) swap( x, y );if( block[x] ^ block[y] ) x = query_top( x );else {if( top[x] ^ top[y] ) x = query_top( x ), y = query_top( y );else break;}}while( x ^ y ) {if( x < y ) swap( x, y );x = query_a( x );}return x; }int main() {scanf( "%d %d", &n, &Q );B = sqrt( n ), B_cnt = ( n - 1 ) / B + 1;for( int i = 2;i <= n;i ++ ) {scanf( "%d", &a[i] );block[i] = ( i - 1 ) / B + 1;}for( int i = 1;i <= block[n];i ++ ) L[i] = ( i - 1 ) * B + 1, R[i] = min( n, i * B ), pushup( i );for( int i = 1, opt, l, r, x;i <= Q;i ++ ) {scanf( "%d %d %d", &opt, &l, &r );if( opt & 1 ) scanf( "%d", &x ), modify( l, r, x );else printf( "%d\n", lca( l, r ) );}return 0; }總結(jié)
以上是生活随笔為你收集整理的CF1491H Yuezheng Ling and Dynamic Tree(分块)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WiDi无线投屏怎么用苹果电脑如何无线投
- 下一篇: XFTP无法传输_xftp软件,比xft