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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

[LOJ3153] 三级跳(单调栈 + 线段树)

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

problem

loj3153

solution

有一個顯然正確但又不起眼卻是正解必備的結論:

考慮 (x,y,z)(x,y,z)(x,y,z) 答案三元對,如果有一個數 i∈(x,y)∧ai≥axi\in(x,y)\wedge a_i\ge a_xi(x,y)ai?ax?,那么 (i,y,z)(i,y,z)(i,y,z) 一定是不劣于 (x,y,z)(x,y,z)(x,y,z) 的。

于是乎,我們就想到了用單調棧找出這樣的 (i,y)(i,y)(i,y) 點對。

  • 具體而言:

    gi:g_i:gi?: 存儲所有 (i,y)(i,y)(i,y)yyy

    維護一個遞減的單調棧,從 111nnn 開始枚舉,如果枚舉到的 iiiai>as.top()a_i>a_{s.top()}ai?>as.top()? 就彈棧,且把 iii 放入 gs.top()g_{s.top()}gs.top()?,彈到 ai≤as.top()a_i\le a_{s.top()}ai?as.top()? 為止。

    如果棧頂還有元素,就再把 iii 放入 gs.top()g_{s.top()}gs.top()?

    最后把 iii 入棧。

    這樣所有 (i,y)(i,y)(i,y) 點對都掛在了 iii 的下面。

處理出所有的點對后,我們把所有詢問 [l,r][l,r][l,r] 掛在 lll 下面。

從大到小枚舉 iii

先把 gi:(i,y)g_i:(i,y)gi?:(i,y) 所有點對信息更改,當 z≥y?2?iz\ge y*2-izy?2?i 時,(i,y,z)(i,y,z)(i,y,z) 就是一個合法三元對。

這個時候的 zzz 對應著一段區間,我們容易想到線段樹修改。

維護一棵線段樹,樹上每個節點表示做 zzz 時的最大 ax+ay+aza_x+a_y+a_zax?+ay?+az?

ai+aya_i+a_yai?+ay? 修改 [y?2?i,n][y*2-i,n][y?2?i,n] 區間,初始建樹時就已經把 aza_zaz? 掛在 zzz 節點上面了。

然后查詢 l=il=il=i 的所有詢問,在線段樹上查詢 [l,r][l,r][l,r] 區間。

這也是為什么要從大到小枚舉的原因。

線段樹具體維護可見代碼。

code

#include <bits/stdc++.h> using namespace std; #define int long long #define maxn 500005 int n, Q; int ans[maxn], a[maxn]; stack < int > s; vector < int > g[maxn]; vector < pair < int, int > > q[maxn];namespace SGT {struct node { int sum, tag, Max; }t[maxn << 2];#define lson now << 1#define rson now << 1 | 1#define mid (l + r >> 1)void pushdown( int now ) {if( ! t[now].tag ) return;t[lson].tag = max( t[lson].tag, t[now].tag );t[lson].Max = max( t[lson].Max, t[lson].sum + t[now].tag );t[rson].tag = max( t[rson].tag, t[now].tag );t[rson].Max = max( t[rson].Max, t[rson].sum + t[now].tag );t[now].tag = 0;}void build( int now, int l, int r ) {if( l == r ) { t[now].sum = a[l]; return; }build( lson, l, mid );build( rson, mid + 1, r );t[now].sum = max( t[lson].sum, t[rson].sum );}void modify( int now, int l, int r, int L, int R, int val ) {if( R < l or r < L or L > R ) return;if( L <= l and r <= R ) {t[now].tag = max( t[now].tag, val );t[now].Max = max( t[now].Max, t[now].sum + val );return;}pushdown( now );modify( lson, l, mid, L, R, val );modify( rson, mid + 1, r, L, R, val );t[now].Max = max( t[lson].Max, t[rson].Max );}int query( int now, int l, int r, int L, int R ) {if( R < l or r < L ) return -1e9;if( L <= l and r <= R ) return t[now].Max;pushdown( now );return max( query( lson, l, mid, L, R ), query( rson, mid + 1, r, L, R ) );} }signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) {scanf( "%lld", &a[i] );while( ! s.empty() and a[s.top()] < a[i] ) g[s.top()].push_back( i ), s.pop();if( ! s.empty() ) g[s.top()].push_back( i );s.push( i );}SGT :: build( 1, 1, n );scanf( "%lld", &Q );for( int i = 1, l, r;i <= Q;i ++ ) {scanf( "%lld %lld", &l, &r );q[l].push_back( make_pair( r, i ) );}for( int i = n;i;i -- ) {for( int j : g[i] )SGT :: modify( 1, 1, n, j * 2 - i, n, a[i] + a[j] );for( auto it : q[i] )ans[it.second] = SGT :: query( 1, 1, n, i, it.first );}for( int i = 1;i <= Q;i ++ )printf( "%lld\n", ans[i] );return 0; } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

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

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