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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

编程问答

CF1270H Number of Components(线段树)

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

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?,則一定有一個(gè) 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)通。

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

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

考慮相鄰兩個(gè)連通塊,假設(shè)前一個(gè)聯(lián)通塊的左右端點(diǎn)為 l1,r1l_1,r_1l1?,r1?,則后一個(gè)聯(lián)通塊的左右端點(diǎ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?]} 兩個(gè)聯(lián)通塊才不會(huì)合并。

進(jìn)一步講,點(diǎn) kkk 能夠成為一個(gè)連通塊的分?jǐn)帱c(diǎn),當(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,將這個(gè)新數(shù)組表示為 f(k)f(k)f(k),與 kkk 有關(guān)。

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

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

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

換個(gè)角度講,令 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) 的長(zhǎng)相一定也是 111...11?k000...00\underbrace{111...11}_{k}000...00k111...11??000...00

確定一個(gè)滿足條件的 www 后的 kkk 也是唯一的。所以沒(méi)必要枚舉斷點(diǎn) kkk,只需要枚舉 www 即可。

也就是說(shuō),只需要統(tǒng)計(jì)有多少個(gè) www 對(duì)應(yīng)的 f(w)f(w)f(w) 長(zhǎng)相是這樣的,即有且僅有一對(duì)相鄰的 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]} 的情況,這個(gè)時(shí)候是沒(méi)有一對(duì) 101010 的。

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

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

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

考慮修改 aia_iai? ,會(huì)對(duì) 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?}) 時(shí) ai?1,aia_{i-1},a_iai?1?,ai? 會(huì)構(gòu)成一對(duì) 010101,在線段樹上將這個(gè)區(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 至少都會(huì)有 111 對(duì) 010101

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

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

當(dāng)然要注意,只有當(dāng)前出現(xiàn)在 aaa 數(shù)組里的 www,即 w=aiw=a_iw=ai?,才能在線段樹中統(tǒng)計(jì)代表 www 的葉子節(jié)點(diǎn)是否貢獻(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(线段树)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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