CF1482E Skyline Photo
Description
Alice is visiting New York City. To make the trip fun, Alice will take photos of the city skyline and give the set of photos as a present to Bob. However, she wants to find the set of photos with maximum beauty and she needs your help.
There are $n$ buildings in the city, the $i$-th of them has positive height $h_i$. All $n$ building heights in the city are different. In addition, each building has a beauty value $b_i$. Note that beauty can be positive or negative, as there are ugly buildings in the city too.
A set of photos consists of one or more photos of the buildings in the skyline. Each photo includes one or more buildings in the skyline that form a contiguous segment of indices. Each building needs to be in exactly one photo. This means that if a building does not appear in any photo, or if a building appears in more than one photo, the set of pictures is not valid.
The beauty of a photo is equivalent to the beauty $b_i$ of the shortest building in it. The total beauty of a set of photos is the sum of the beauty of all photos in it. Help Alice to find the maximum beauty a valid set of photos can have.
Solution
设$dp_i$表示考虑前$i$个建筑的答案,求出$i$前面的第一个高度比$h_i$小的位置$j$,可以用单调队列求出
如果$j$与$i$在同一张照片,此时的答案就是$dp_j$
如果$j$与$i$不在同一张照片,因为$i$是$(j,i]$中最低的,所以此时的答案就是$dp_k+b_i$,其中$j \leq k < i$,可以用线段树求出
时间复杂度$O(n \log n)$
#include<iostream> #include<cstdio> #include<cmath> using namespace std; int n,h[300005],b[300005],sta[300005],top,L[300005]; long long dp[300005],val[1200005]; const long long inf=0x7f7f7f7f7f7f7f7f; inline int read(){ int f=1,w=0; char ch=0; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=getchar(); return f*w; } void build(int i,int l,int r){ val[i]=-inf; if(l==r)return; int mid=l+r>>1; build(i<<1,l,mid),build(i<<1|1,mid+1,r); } long long query(int i,int l,int r,int L,int R){ if(L<=l&&r<=R)return val[i]; int mid=l+r>>1; long long ret=-inf; if(L<=mid)ret=max(ret,query(i<<1,l,mid,L,R)); if(R>mid)ret=max(ret,query(i<<1|1,mid+1,r,L,R)); return ret; } void update(int i,int l,int r,int p,long long v){ if(l==r){val[i]=max(val[i],v);return;} int mid=l+r>>1; if(p<=mid)update(i<<1,l,mid,p,v); else update(i<<1|1,mid+1,r,p,v); val[i]=max(val[i<<1],val[i<<1|1]); } int main(){ n=read(); for(int i=1;i<=n;i++)h[i]=read(); for(int i=1;i<=n;i++)b[i]=read(); build(1,0,n),dp[0]=-inf,update(1,0,n,0,0); for(int i=1;i<=n;i++){ while(top&&h[sta[top]]>=h[i])--top; L[i]=sta[top],sta[++top]=i,dp[i]=max(query(1,0,n,L[i],i-1)+b[i],dp[L[i]]),update(1,0,n,i,dp[i]); } printf("%lld\n",dp[n]); return 0; }