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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

[CF 526 F] Pudding Monsters(单调栈 + 线段树)

發布時間:2023/12/3 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [CF 526 F] Pudding Monsters(单调栈 + 线段树) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

CF526F Pudding Monsters

  • problem
  • solution
  • code

problem

luogu翻譯

solution

observation :每行每列恰好有一個棋子,所以如果一段區間 [l,r][l,r][l,r] 會被某個 kkk 統計,當且僅當這個區間內棋子縱坐標 ymax?ymin+1=r?l+1y_{max}-y_{min}+1=r-l+1ymax??ymin?+1=r?l+1

發現這是經典的連續段計數問題

標配:單調棧 +++ 線段樹。

將所有棋子按照橫坐標升序排序。

枚舉右端點 rrr,線段樹上每個葉子節點 lll 維護的是 [l,r][l,r][l,r] 的信息。

轉換一下條件判定:ymax?ymin+l?r=0y_{max}-y_{min}+l-r=0ymax??ymin?+l?r=0

因為每行每列恰好一個棋子,所以所有情況都有 ymax?ymin≥r?ly_{max}-y_{min}\ge r-lymax??ymin?r?l

而最后要計入答案的是取等的情況,即最小值。

所以線段樹就維護 ymax?ymin+l?ry_{max}-y_{min}+l-rymax??ymin?+l?r 的最小值,以及最小值個數。

最后統計的時候,就統計最小值為 000 的節點信息。

  • rrr 每次都是 +1+1+1,對應的是線段樹整體 ?1-1?1

  • lllrrr 無關,在最開始建樹是加上即可。

  • ymaxy_{max}ymax?,維護一個單增棧,棧中第 toptoptop 個元素維護的是區間 [sMax[top?1]+1,sMax[top]]\Big[sMax[top-1]+1,sMax[top]\Big][sMax[top?1]+1,sMax[top]] 的最大值信息,即這一段的縱坐標最大值都是 sMax[top]sMax[top]sMax[top]

    每次用右端點 rrr 與棧比較縱坐標大小,如果 rrr 大則彈棧,將 toptoptop 維護的區間加上 yr?ysMax[top]y_r-y_{sMax[top]}yr??ysMax[top]?

  • yminy_{min}ymin?,維護一個單減棧,棧中第 toptoptop 個元素維護的是區間 [sMin[top?1]+1,sMin[top]]\Big[sMin[top-1]+1,sMin[top]\Big][sMin[top?1]+1,sMin[top]] 的最大值信息,即這一段的縱坐標最小值都是 sMin[top]sMin[top]sMin[top]

    每次用右端點 rrr 與棧比較縱坐標大小,如果 rrr 小則彈棧,將 toptoptop 維護的區間加上 ysMin[top]?yiy_{sMin[top]-y_i}ysMin[top]?yi??

事件復雜度為 O(nlog?n)O(n\log n)O(nlogn)

code

#include <bits/stdc++.h> using namespace std; #define maxn 300005 int n, tMax, tMin; int x[maxn], y[maxn], id[maxn], sMax[maxn], sMin[maxn]; struct node { int tag, Min, cnt; }t[maxn << 2];#define lson now << 1 #define rson now << 1 | 1 #define mid ( ( l + r ) >> 1 )void pushup( int now ) {if( t[lson].Min < t[rson].Min ) t[now].Min = t[lson].Min, t[now].cnt = t[lson].cnt;else if( t[lson].Min > t[rson].Min ) t[now].Min = t[rson].Min, t[now].cnt = t[rson].cnt;else t[now].Min = t[lson].Min, t[now].cnt = t[lson].cnt + t[rson].cnt; }void pushdown( int now ) {if( t[now].tag ) {t[lson].tag += t[now].tag;t[rson].tag += t[now].tag;t[lson].Min += t[now].tag;t[rson].Min += t[now].tag;t[now].tag = 0;return;} }void build( int now, int l, int r ) {if( l == r ) { t[now].Min = l, t[now].cnt = 1; return; }build( lson, l, mid );build( rson, mid + 1, r );pushup( now ); }void modify( int now, int l, int r, int L, int R, int k ) {if( R < l or r < L ) return;if( L <= l and r <= R ) { t[now].Min += k, t[now].tag += k; return; }pushdown( now );modify( lson, l, mid, L, R, k );modify( rson, mid + 1, r, L, R, k );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].Min ? 0 : t[now].cnt;return query( lson, l, mid, L, R ) + query( rson, mid + 1, r, L, R ); }int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ ) scanf( "%d %d", &x[i], &y[i] ), id[i] = i;sort( id + 1, id + n + 1, []( int u, int v ) { return x[u] < x[v]; } );build( 1, 1, n );long long ans = 0;for( int i = 1;i <= n;i ++ ) {modify( 1, 1, n, 1, n, -1 );modify( 1, 1, n, x[sMax[tMax]] + 1, i, y[id[i]] );modify( 1, 1, n, x[sMin[tMin]] + 1, i, -y[id[i]] );while( tMax and y[sMax[tMax]] < y[id[i]] ) {modify( 1, 1, n, x[sMax[tMax - 1]] + 1, x[sMax[tMax]], y[id[i]] - y[sMax[tMax]] );tMax --;}while( tMin and y[sMin[tMin]] > y[id[i]] ) {modify( 1, 1, n, x[sMin[tMin - 1]] + 1, x[sMin[tMin]], y[sMin[tMin]] - y[id[i]] );tMin --;}sMax[++ tMax] = sMin[++ tMin] = id[i];ans += query( 1, 1, n, 1, i );}printf( "%lld\n", ans );return 0; }

總結

以上是生活随笔為你收集整理的[CF 526 F] Pudding Monsters(单调栈 + 线段树)的全部內容,希望文章能夠幫你解決所遇到的問題。

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