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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CF1270H Number of Components(线段树)

發(fā)布時間:2023/12/3 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CF1270H Number of Components(线段树) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

problem

洛谷鏈接

solution

定理 若 i<ji<ji<ji,ji,ji,j 聯(lián)通,則必有 k∈(i,j)k\in(i,j)k(i,j) 也與 i,ji,ji,j 聯(lián)通。

下面給出證明,挺顯然的。

  • ai<aja_i<a_jai?<aj?,則一定有 ai<ak∨ak<aja_i<a_k\vee a_k<a_jai?<ak?ak?<aj? 成立。
  • ai>aja_i>a_jai?>aj?,則一定有一個 x<ix<ix<i 滿足 ax<ai∧ax<aja_x<a_i\wedge a_x<a_jax?<ai?ax?<aj? 使得 i,ji,ji,j 間接聯(lián)通。
    • ak<axa_k<a_xak?<ax?,則有 k?jk-jk?j 聯(lián)通。
    • ax<aka_x<a_kax?<ak?,則有 k?xk-xk?x 聯(lián)通。

所以一個連通塊一定對應(yīng)的是數(shù)組 aaa 的一段連續(xù)區(qū)間。

也就是說,所有連通塊將數(shù)組劃分成若干個互不相交且并集為整個數(shù)組的區(qū)間。

考慮相鄰兩個連通塊,假設(shè)前一個聯(lián)通塊的左右端點為 l1,r1l_1,r_1l1?,r1?,則后一個聯(lián)通塊的左右端點為 r1+1(l2),r2r_1+1(l_2),r_2r1?+1(l2?),r2?。

當(dāng)且僅當(dāng) min?{ai∣i∈[l1,r1]}>max?{ai∣i∈[l2,r2]}\min\{a_i|i\in [l_1,r_1]\}>\max\{a_i|i\in[l_2,r_2]\}min{ai?i[l1?,r1?]}>max{ai?i[l2?,r2?]} 兩個聯(lián)通塊才不會合并。

進(jìn)一步講,點 kkk 能夠成為一個連通塊的分?jǐn)帱c,當(dāng)且僅當(dāng) min?{ai∣i≤k}>max?{ai∣k<i}\min\{a_i|i\le k\}>\max\{a_i|k<i\}min{ai?ik}>max{ai?k<i}

不妨將 ai≥aka_i\ge a_kai?ak? 的位置設(shè)為 111ai<aka_i<a_kai?<ak? 的設(shè)為 000,將這個新數(shù)組表示為 f(k)f(k)f(k),與 kkk 有關(guān)。

則發(fā)現(xiàn),當(dāng) kkk 為分?jǐn)帱c的時候,f(k)f(k)f(k) 的長相一定是 111...11?k000...00\underbrace{111...11}_{k}000...00k111...11??000...00。

換言之,當(dāng) kkk 為分?jǐn)帱c的時候,f(k)f(k)f(k)ai≠ai+1a_i\neq a_{i+1}ai??=ai+1?iii 有且僅有一個。

當(dāng)然 f(k)f(k)f(k) 的長相有很多種。但如果 kkk 成為分?jǐn)帱c那么 f(k)f(k)f(k) 就只能有一種長相。

換個角度講,令 w=max?{ai∣k<i}w=\max\{a_i|k<i\}w=max{ai?k<i},將 >w>w>w 的位置設(shè)為 111≤w\le ww 的設(shè)為 000,將新數(shù)組依舊表示為 f(w)f(w)f(w)。

f(w)f(w)f(w) 的長相一定也是 111...11?k000...00\underbrace{111...11}_{k}000...00k111...11??000...00。

確定一個滿足條件的 www 后的 kkk 也是唯一的。所以沒必要枚舉斷點 kkk,只需要枚舉 www 即可。

也就是說,只需要統(tǒng)計有多少個 www 對應(yīng)的 f(w)f(w)f(w) 長相是這樣的,即有且僅有一對相鄰的 101010。

為了規(guī)避全 000 和全 111,也就是 w=min?/max?{ai∣i∈[1,n]}w=\min/\max\{a_i|i\in[1,n]\}w=min/max{ai?i[1,n]} 的情況,這個時候是沒有一對 101010 的。

不妨令 a0=∞,an+1=0a_0=∞,a_{n+1}=0a0?=,an+1?=0。則滿足條件的 wwwf(w)f(w)f(w) 有且僅有一對相鄰的 101010。

以權(quán)值 www 為下標(biāo)建立線段樹,記錄每個葉子對應(yīng) f(x)f(x)f(x) 長相中 101010 的對數(shù)。

最后統(tǒng)計多少個位置的對數(shù)為 111 即可。

考慮修改 aia_iai? ,會對 w∈[min?{ai?1,ai},max?{ai?1,ai})?[min?{ai,ai+1},max?{ai,ai+1})w\in\Big[\min\{a_{i-1},a_i\},\max\{a_{i-1},a_{i}\}\Big)\bigcup\Big[\min\{a_{i},a_{i+1}\},\max\{a_{i},a_{i+1}\}\Big)w[min{ai?1?,ai?},max{ai?1?,ai?})?[min{ai?,ai+1?},max{ai?,ai+1?}) 造成貢獻(xiàn)變化。

例如 w∈[min?{ai?1,ai},max?{ai?1,ai})w\in\Big[\min\{a_{i-1},a_i\},\max\{a_{i-1},a_{i}\}\Big)w[min{ai?1?,ai?},max{ai?1?,ai?})ai?1,aia_{i-1},a_iai?1?,ai? 會構(gòu)成一對 010101,在線段樹上將這個區(qū)間整體 +1+1+1 即可。

注意到 ai?1,ai+1a_{i-1},a_{i+1}ai?1?,ai+1? 可能越界,不妨設(shè) a0=lim?,an+1=0a_0=\lim,a_{n+1}=0a0?=lim,an+1?=0,那么不管 iii 位置,所有 www 至少都會有 111010101。

線段樹很難做到快速查詢哪些位置是 111。但是現(xiàn)在所有的 www010101 個數(shù) ≥1\ge 11。

就可以用線段樹統(tǒng)計最小值和個數(shù)了。當(dāng)且僅當(dāng)最小值為 111 的時候再記錄答案即可。

當(dāng)然要注意,只有當(dāng)前出現(xiàn)在 aaa 數(shù)組里的 www,即 w=aiw=a_iw=ai?,才能在線段樹中統(tǒng)計代表 www 的葉子節(jié)點是否貢獻(xiàn)。

code

#include <bits/stdc++.h> using namespace std; #define maxn 500005 #define lim 1000001 int n, q; int a[maxn]; struct node { int sum, tag, cnt; }t[lim + 5 << 2];#define lson now << 1 #define rson now << 1 | 1 #define mid (l + r >> 1)void pushup( int now ) {if( t[lson].sum < t[rson].sum ) t[now].sum = t[lson].sum, t[now].cnt = t[lson].cnt;else if( t[lson].sum > t[rson].sum ) t[now].sum = t[rson].sum, t[now].cnt = t[rson].cnt;elset[now].sum = t[lson].sum, t[now].cnt = t[lson].cnt + t[rson].cnt; }void pushdown( int now ) {if( t[now].tag ) {t[lson].sum += t[now].tag;t[rson].sum += t[now].tag;t[lson].tag += t[now].tag;t[rson].tag += t[now].tag;t[now].tag = 0;} }void modify( int now, int l, int r, int L, int R, int x ) {if( R < l or r < L ) return;if( L <= l and r <= R ) {t[now].sum += x;t[now].tag += x;return;}pushdown( now );modify( lson, l, mid, L, R, x );modify( rson, mid + 1, r, L, R, x );pushup( now ); }void modify( int now, int l, int r, int pos, int x ) {if( l == r ) { t[now].cnt += x; return; }pushdown( now );if( pos <= mid ) modify( lson, l, mid, pos, x );else modify( rson, mid + 1, r, pos, x );pushup( now ); }int query( int now, int l, int r, int L, int R ) {if( R < l or r < L ) return 0;if( L <= l and r <= R ) return t[now].sum == 1 ? t[now].cnt : 0;pushdown( now );return query( lson, l, mid, L, R ) + query( rson, mid + 1, r, L, R ); }void modify( int l, int r, int x ) {if( l == r ) return;if( l > r ) swap( l, r );modify( 1, 0, lim, l, r - 1, x ); }int main() {scanf( "%d %d", &n, &q );for( int i = 1;i <= n;i ++ ) scanf( "%d", &a[i] );a[0] = lim;for( int i = 0;i <= n;i ++ ) {modify( a[i], a[i + 1], 1 );modify( 1, 0, lim, a[i], 1 );}while( q -- ) {int pos, x;scanf( "%d %d", &pos, &x );modify( a[pos - 1], a[pos], -1 );modify( a[pos], a[pos + 1], -1 );modify( 1, 0, lim, a[pos], -1 );a[pos] = x;modify( a[pos - 1], a[pos], 1 );modify( a[pos], a[pos + 1], 1 );modify( 1, 0, lim, a[pos], 1 );printf( "%d\n", query( 1, 0, lim, 1, lim - 1 ) );}return 0; }

總結(jié)

以上是生活随笔為你收集整理的CF1270H Number of Components(线段树)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。