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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

CF1491H Yuezheng Ling and Dynamic Tree(分块)

發布時間:2023/12/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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?個數,記第iii個塊的左右邊界為Li,RiL_i,R_iLi?,Ri?,記第iii個數所在塊為blockiblock_iblocki?

定義topitop_itopi?節點iii的祖先中,與iii不在同一個塊的最大編號點

【這個真的很妙,可以說是這道題的解法考察點了】

問題是如何在al,ra_{l,r}al,r?更新時,對某個塊xxx內的被覆蓋節點i∈[l,r]i\in[l,r]i[l,r]topitop_itopi?進行更新??

  • 如果更新后的ai<Lxa_i<L_xai?<Lx?,則aia_iai?成為新的滿足toptoptop定義的最大編號點【iii的祖先都已經全變成了aia_iai?的祖先,再加個aia_iai?本身】,topi=aitop_i=a_itopi?=ai?
  • 如果更新后的aia_iai?仍然屬于塊xxx內,則直接鏈接過去,topi=topaitop_i=top_{a_i}topi?=topai??

明白了如何維護塊內信息,接下來就是對不同塊進行操作了

首先考慮修改操作

  • 散塊(只覆蓋了塊內部分點):直接暴力修改點的aia_iai?值,然后暴力重構,單次操作時間復雜度O(n)O(\sqrt{n})O(n?)

  • 整塊:懶標記tagitag_itagi?表示點iiiaia_iai?還沒減多少【比真實的aia_iai?多了tagitag_itagi?,未真實操作修改】,但這個時候塊內某些點的topitop_itopi?可能已經發生了變化,沒有實時更新就會影響后面的查詢操作,而每次暴力修改又需要整個塊的遍歷,多個整塊幾乎就是O(O(O(修改區間長度)))的,無法保證時間復雜度

    實際上,發現對于每個塊,經過n\sqrt{n}n?次整塊修改操作后,aia_iai?都至少會變為ai?na_i-\sqrt{n}ai??n?一定在當前塊前面的塊

    因此,我們可以維護每個塊被修改的次數cntxcnt_xcntx?cntx>ncnt_x>\sqrt{n}cntx?>n?,就不再暴力修改整塊,而是直接整塊的區間減法,這個時候的aia_iai?一定是其的topitop_itopi?,否則就暴力修改

    每個塊最多修改n\sqrt{n}n?次,每次需要O(n)O(\sqrt{n})O(n?)遍歷修改,一共有n\sqrt{n}n?個塊,總時間復雜度是O(nn)O(n\sqrt{n})O(nn?)

接著考慮詢問操作

lca\text{lca}lca肯定是倍增暴力啦!這里直接使用暴力爬山法

考慮詢問u,vu,vu,v兩個點的lcalcalca

  • blocku≠blockvblock_u\neq block_vblocku??=blockv?,則選擇對應blockblockblock編號較大的點,跳到其toptoptop

  • blocku=blockvblock_u=block_vblocku?=blockv?topu≠topvtop_u\neq top_vtopu??=topv?,則兩個節點一起跳對應的toptoptop

  • blocku=blockvblock_u=block_vblocku?=blockv?topu=topvtop_u=top_vtopu?=topv?,則一直讓節點編號大的點跳父親aaa,直到兩點相同為止

    【注意在跳的時候,一定要減去所在塊的tagxtag_xtagx?標記,才能得到真正的top/atop/atop/a

一個點跳toptoptop的次數最多為nn=n\frac{n}{\sqrt{n}}=\sqrt{n}n?n?=n?次,跳完toptoptop就是在一個塊里面的跳aaa,最多也是n\sqrt{n}n?次,所以單次詢問時間復雜度為O(n)O(\sqrt{n})O(n?)

本題最終的時間復雜度為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; }

總結

以上是生活随笔為你收集整理的CF1491H Yuezheng Ling and Dynamic Tree(分块)的全部內容,希望文章能夠幫你解決所遇到的問題。

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