题意
输入整数n,给出两个包含n个整数的序列a和b,找到一个区间[l,r],使在该区间内a序列最小值×b序列区间和的值最大。

题解
遍历a序列,维护单调栈求以当前值a[i]为最小值时的最大可达区间[ L[i],R[i] ](即最大左右边界);
b序列先预处理其前缀和pre_sum,后用线段树维护pre_sum数组的区间最值;所以答案就是a[i]×b序列在[ L[i],R[i] ]区间内的和的最大值,不断更新最优解求最大结果即可。
当a[i]≥0时,b序列在[ L[i],R[i] ]区间内的和的最大值为b序列前缀和数组后半部分最大值-前半部分最小值,即:
max( [pre_sum(i),pre_sum(R[i])] )-min( [pre_sum(L[i]-1),pre_sum(i-1)] );
当a[i]<0时,b序列在[ L[i],R[i] ]区间内的和的最大值为b序列前缀和数组后半部分最小值-前半部分最大值,即:
min( [pre_sum(i),pre_sum(R[i])] )-max( [pre_sum(L[i]-1),pre_sum(i-1)] );
时间复杂度O(nlogn)。
Code

1 /*2442ms*/
2 #include<bits/stdc++.h>
3 using namespace std;
4 typedef long long ll;
5 const int maxn=3e6+5;
6 const ll inf=0x3f3f3f3f3f3f3f3fLL;
7 ll a[maxn],b[maxn],pre_sum[maxn],L[maxn],R[maxn],sta[maxn];
8 struct node
9 {
10 int l,r;//区间[l,r]
11 ll mx;//区间最大值
12 ll mn;//区间最小值
13 }tree[maxn<<2];//一定要开到4倍多的空间
14 void pushup(int index)
15 {
16 tree[index].mx=max(tree[index<<1].mx,tree[index<<1|1].mx);
17 tree[index].mn=min(tree[index<<1].mn,tree[index<<1|1].mn);
18 }
19 void build(int l,int r,int index)
20 {
21 tree[index].l=l;
22 tree[index].r=r;
23 if(l==r){
24 tree[index].mn=tree[index].mx=pre_sum[l];
25 return;
26 }
27 int mid=(l+r)>>1;
28 build(l,mid,index<<1);
29 build(mid+1,r,index<<1|1);
30 pushup(index);
31 }
32 ll queryMIN(int l,int r,int index)
33 {
34 if(l<=tree[index].l&&r>=tree[index].r)
35 return tree[index].mn;
36 int mid=(tree[index].l+tree[index].r)>>1;
37 ll Min=inf;
38 if(l<=mid)
39 Min=min(queryMIN(l,r,index<<1),Min);
40 if(r>mid)
41 Min=min(queryMIN(l,r,index<<1|1),Min);
42 return Min;
43 }
44 ll queryMAX(int l,int r,int index)
45 {
46 if(l<=tree[index].l&&r>=tree[index].r)
47 return tree[index].mx;
48 int mid=(tree[index].l+tree[index].r)>>1;
49 ll Max=-inf;
50 if(l<=mid)
51 Max = max(queryMAX(l,r,index<<1),Max);
52 if(r>mid)
53 Max = max(queryMAX(l,r,index<<1|1),Max);
54 return Max;
55 }
56 int main()
57 {
58 int n;
59 while(~scanf("%d",&n))
60 {
61 for(int i=1;i<=n;i++)
62 scanf("%lld",&a[i]);
63 for(int i=1;i<=n;i++){
64 scanf("%lld",&b[i]);
65 pre_sum[i]=pre_sum[i-1]+b[i];//求b序列前缀和
66 }
67 build(0,n,1);
68 /*单调栈求左端点L[i]*/
69 int top=0;
70 for(int i=1;i<=n;i++){
71 while(top&&a[i]<=a[sta[top]])
72 top--;
73 L[i]=(top==0)?1:sta[top]+1;
74 sta[++top]=i;
75 }
76 /*单调栈求右端点R[i]*/
77 top=0;
78 for(int i=n;i>=1;i--){
79 while(top&&a[i]<=a[sta[top]])
80 top--;
81 R[i]=(top==0)?n:sta[top]-1;
82 sta[++top]=i;
83 }
84
85 ll ans=-inf;
86 for(int i=1;i<=n;i++){
87 ll cnt=0;
88 if(a[i]>0){
89 cnt=(queryMAX(i,R[i],1)-queryMIN(L[i]-1,i-1,1))*a[i];
90 }
91 else if(a[i]<0){
92 cnt=(queryMIN(i,R[i],1)-queryMAX(L[i]-1,i-1,1))*a[i];
93 }
94 else if(a[i]==0)
95 cnt=0;
96 if(cnt>ans)ans=cnt;
97 }
98 printf("%lld\n",ans);
99 }
100 return 0;
101 }
102
103 /*
104 7
105 -519 9794 1664 8189 -295 3471 1104
106 -1796 -3137 7098 -3333 4683 -3968 467 3
107 11811072
108 */
109 /*
110 18
111 -273 7169 -8145 -6664 -2970 698 8701 -6791 459 -5678 -846 8072 6384 5051 -3606 -4737 -9928 6815
112 1609 -8810 9205 -9129 -1919 -116 -6752 385 4347 614 6261 4399 -8961 1022 -1360 -5074 7825 -122
113 142708545
114 */
