南昌网络赛 I. Max answer (单调栈 + 线段树)
https://nanti.jisuanke.com/t/38228
题意
给你一个序列,对于每个连续子区间,有一个价值,等与这个区间和×区间最小值,
求所有子区间的最大价值是多少。
分析:我们先用单调栈预处理 区间 [L[i] , R[i] ] 最小值为a[i] , 的L[i] , R[i] ;
首先我们明白 , 如果a[i] >0 那 [L[i] , R[i] ] , 里面的数都是正数 , 所以应该全选 ;
a[i] < 0 , 那我们 应该在[L[i]-1 , i-1] 这里面找到前缀和最大 , 在[i,R[i]] 这里找到前缀和最小
这样的区间和才是最大
我。。。比赛的时候被自己秀死 , 判断a[i] >0 竟然也用了线段树的做法 , 导致边界没有控制好
#include <iostream> #include <string.h> #include <algorithm> #include <stdio.h> #include <math.h> #include <queue> #define MAXN 500001 #define inf 0x3f3f3f3f using namespace std; const int N=500001; typedef long long ll; int a[N],L[N],R[N],s[N],top; ll sum[N],ans=-0x7f7f7f7f,n,h[N]; ll l=1,r=1; struct node{ int l,r;//区间[l,r] ll mx; //区间最大值 ll mn; //区间最小值 }tree[MAXN<<2];//一定要开到4倍多的空间 void pushup(int index){ tree[index].mx = max(tree[index<<1].mx,tree[index<<1|1].mx); tree[index].mn = min(tree[index<<1].mn,tree[index<<1|1].mn); } int cnt; void build(int l,int r,int index){ tree[index].l = l; tree[index].r = r; if(l == r){ // scanf("%d",&tree[index].sum); tree[index].mn = tree[index].mx =sum[++cnt]; return ; } int mid = (l+r)>>1; build(l,mid,index<<1); build(mid+1,r,index<<1|1); pushup(index); } ll queryMIN(int l,int r,int index){ if(l <= tree[index].l && r >= tree[index].r){ //return tree[index].sum; return tree[index].mn; } int mid = (tree[index].l+tree[index].r)>>1; ll Min =0x7f7f7f7f; if(l <= mid){ // Max = max(query(l,r,index<<1),Max); Min = min(queryMIN(l,r,index<<1),Min); } if(r > mid){ // Max = max(query(l,r,index<<1|1),Max); Min = min(queryMIN(l,r,index<<1|1),Min); } //return ans; return Min; //return Min; } ll queryMAX(int l,int r,int index){ if(l <= tree[index].l && r >= tree[index].r){ //return tree[index].sum; return tree[index].mx; //return tree[index].mn; } int mid = (tree[index].l+tree[index].r)>>1; ll Max = -0x7f7f7f7f; if(l <= mid){ Max = max(queryMAX(l,r,index<<1),Max); // Min = min(query(l,r,index<<1),Min); } if(r > mid){ Max = max(queryMAX(l,r,index<<1|1),Max); //Min = min(query(l,r,index<<1|1),Min); } //return ans; return Max; //return Min; } int main() { ios::sync_with_stdio(false); cin>>n; memset(sum,0,sizeof(sum)); for(int i=1;i<=n;i++) { cin>>a[i]; sum[i]=sum[i-1]+a[i]; } build(1,n+1,1); top=0; for(int i=1;i<=n;i++) { while(top&&a[s[top]]>=a[i]) --top; L[i]=(top==0?1:s[top]+1); s[++top]=i; } top=0; for(int i=n;i>=1;i--) { while(top&&a[s[top]]>=a[i]) --top; R[i]=(top==0?n:s[top]-1); s[++top]=i; } // cout<<queryMIN(2,2,1)<<endl; for(int i=1;i<=n;i++) { ll temp; if(a[i]>0) { temp =(sum[R[i]] - sum[L[i]-1])*a[i]; // cout<<L[i]<<" "<<R[i]<<endl; // cout<<queryMAX(i,R[i],1)<<" "<<queryMIN(L[i]-1,i-1,1)<<endl; } else if(a[i]<0) { if(L[i]==1 && queryMAX(max(1,L[i]-1),max(1,i-1),1)<0) temp=(queryMIN(i,R[i],1))*a[i]; else temp =(queryMIN(i,R[i],1)-queryMAX(max(1,L[i]-1),max(1,i-1),1))*a[i]; // cout<<queryMAX(L[i]-1,i-1,1)<<" "<<queryMIN(i,R[i],1)<<endl; } else if(a[i]==0) temp=0; // else if(a[i]<0) // { // temp=(queryMIN(R[i],i,1) - queryMAX(L[i],i,1))*a[i]; // } if(temp>ans) {ans=temp;} } cout<<ans<<endl; }