P9485
VioletIsMyLove · · 题解
首先我们看看如果这道题不能改变海拔,它的答案如何计算。
很显然,对于每个
对于总贡献,只需要调用两个单调栈就能计算。
那如果可以改变海拔呢?
对于任何一个
首先考虑变高。
如果将
那如果将
根据
因此如果一个点需要可以降低高度,当且仅当它位于从左到右的单调栈或者从右到左的单调栈内,而它如果会产生贡献,只会发生在出现它是
我们会发现,在最开始统计将每个
这题的细节比较多,所以还是放一下代码。
Code:
#include<bits/stdc++.h>
using namespace std;
struct ZS{
long long h,id;
}st[2][1000005];
long long T,n;
long long top[2],TOP[2];
long long a[1000005],b[1000005],c[1000005];
long long S,s,maxl,maxr;
inline int read(){
int ret=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch)){ret=ret*10+ch-'0';ch=getchar();}
return ret*f;
}
int main(){
T=read();
while(T--){
n=read();S=s=maxl=maxr=0;memset(top,0,sizeof top);
for(int i=1;i<=n;i++)a[i]=read();
if(n==1){printf("0\n");continue;}
for(int i=1;i<=n;i++)if(st[0][top[0]].h<=a[i])st[0][++top[0]]=(ZS){a[i],i};
for(int i=n;i>=1;i--)if(st[1][top[1]].h<=a[i])st[1][++top[1]]=(ZS){a[i],i};TOP[0]=top[0];TOP[1]=top[1];top[0]=0;
for(int i=1;i<=n;i++){
if(st[0][top[0]+1].id<=i&&top[0]<TOP[0])maxl=st[0][top[0]++].h;
else if(i-1!=st[0][top[0]].id)maxl=max(maxl,a[i-1]);
if(st[1][top[1]].id<i)top[1]--;
b[i]=max(0ll,min(st[0][top[0]].h,st[1][top[1]].h)-a[i]);
S+=b[i];s=max(s,b[i]);
if(i!=st[0][top[0]].id)c[st[0][top[0]].id]+=b[i]-max(0ll,min(maxl,st[1][top[1]].h)-a[i]);
}
top[1]=0;top[0]=TOP[0];
for(int i=n;i>=1;i--){
if(i<st[0][top[0]].id)top[0]--;
if(i<=st[1][top[1]+1].id&&top[1]<TOP[1])maxr=st[1][top[1]++].h;
else if(i+1!=st[1][top[1]].id)maxr=max(maxr,a[i+1]);
if(i!=st[1][top[1]].id)
c[st[1][top[1]].id]+=b[i]-max(0ll,min(st[0][top[0]].h,maxr)-a[i]);
}
for(int i=1;i<=TOP[0];i++){s=max(s,c[st[0][i].id]);c[st[0][i].id]=0;}
for(int i=1;i<=TOP[1];i++){s=max(s,c[st[1][i].id]);c[st[1][i].id]=0;}
printf("%lld\n",S-s);
}
return 0;
}