傳送門
文章目錄
題意:
思路:
首先一個非常明顯的dpdpdp式子就是f[i]=max(f[j]+val(j+1,i))f[i]=max(f[j]+val(j+1,i))f[i]=max(f[j]+val(j+1,i)),其中val(j+1,i)val(j+1,i)val(j+1,i)是[j+1,i][j+1,i][j+1,i]中高度最小的美麗值,復雜度O(n2)O(n^2)O(n2),考慮如何來優(yōu)化這個式子。
我們注意到,[j+1,i][j+1,i][j+1,i]是當前iii的一個后綴,我們jjj從[1,i?1][1,i-1][1,i?1]枚舉的時候,其高度是單調不減的,這啟發(fā)我們維護一個單調不減的棧,那么對于棧中元素,其管轄的范圍就是[stk[top?1],stk[top]?1][stk[top-1],stk[top]-1][stk[top?1],stk[top]?1],當jjj從這個區(qū)間轉移的時候,就是maxj=stk[top?1]stk[top]?1(f[j]+b[stk[top]])max_{j=stk[top-1]}^{stk[top]-1}(f[j]+b[stk[top]])maxj=stk[top?1]stk[top]?1?(f[j]+b[stk[top]])。
所以我們只需要維護一個fff數(shù)組,能快速將他管轄的區(qū)間加上b[stk[top]]b[stk[top]]b[stk[top]],并且能快速查詢所有f+bf+bf+b的最大值,這個顯然可以用線段樹來實現(xiàn)。
為什么直接查詢非管轄區(qū)域的最大值就行了呢?因為在非其管轄的區(qū)域內,我們每個位置已經(jīng)存了f+bf+bf+b的最大值了,只要他還在棧中,那么他的值就不會改變,所以直接取最大值就好啦。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
;
int a
[N
],b
[N
],stk
[N
],top
;
struct Node {int l
,r
;LL mx
,lazy
;
}tr
[N
<<2];void pushup(int u
) {tr
[u
].mx
=max(tr
[L
].mx
,tr
[R
].mx
);
}void pushdown(int u
) {LL lazy
=tr
[u
].lazy
; tr
[u
].lazy
=0;tr
[L
].mx
+=lazy
; tr
[L
].lazy
+=lazy
;tr
[R
].mx
+=lazy
; tr
[R
].lazy
+=lazy
;
} void build(int u
,int l
,int r
) {tr
[u
]={l
,r
,0};if(l
==r
) return;build(L
,l
,Mid
); build(R
,Mid
+1,r
);
}void modify(int u
,int l
,int r
,LL val
) {if(tr
[u
].l
>=l
&&tr
[u
].r
<=r
) {tr
[u
].mx
+=val
;tr
[u
].lazy
+=val
;return ;}pushdown(u
);if(l
<=Mid
) modify(L
,l
,r
,val
);if(r
>Mid
) modify(R
,l
,r
,val
);pushup(u
);
}LL
query(int u
,int l
,int r
) {if(tr
[u
].l
>=l
&&tr
[u
].r
<=r
) return tr
[u
].mx
;LL ans
=-1e15;pushdown(u
);if(l
<=Mid
) ans
=max(ans
,query(L
,l
,r
));if(r
>Mid
) ans
=max(ans
,query(R
,l
,r
));return ans
;
}int main()
{
LL ans
=0;scanf("%d",&n
);for(int i
=1;i
<=n
;i
++) scanf("%d",&a
[i
]);for(int i
=1;i
<=n
;i
++) scanf("%d",&b
[i
]);build(1,0,n
);for(int i
=1;i
<=n
;i
++) {if(!top
) {modify(1,stk
[top
],i
-1,b
[i
]);LL mx
=query(1,0,i
-1);modify(1,i
,i
,mx
);stk
[++top
]=i
;}else {while(top
&&a
[stk
[top
]]>a
[i
]) {modify(1,stk
[top
-1],stk
[top
]-1,-b
[stk
[top
]]);top
--;}modify(1,stk
[top
],i
-1,b
[i
]);LL mx
=query(1,0,i
-1);modify(1,i
,i
,mx
);stk
[++top
]=i
;}}printf("%lld\n",query(1,n
,n
));return 0;
}
總結
以上是生活随笔為你收集整理的Codeforces Round #709 (Div. 1) C. Skyline Photo dp + 单调栈优化的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。