[ABC282Ex] Min + Sum 题解
考虑对于每一个 \(A_i\),找到左边第一个小于和右边第一个不大于该值的数的下标 \(L_i,R_i\),那么 \(A_i\) 就是所有满足 \(L_i<l\le i\le r<R_i\) 的区间 \([l,r]\) 的最小值。
如果 \(i-L_i<R_i-i\) 则枚举 \(l\),否则枚举 \(r\),再二分找到满足要求的另一个端点的区间即可。
代码:
#include<bits/stdc++.h>
#define ll long long
#define mxn 200003
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rept(i,a,b) for(int i=a;i<b;++i)
#define drep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
int n,tot,q[mxn],l[mxn],r[mxn],rt[mxn];
ll s,mx,ans,a[mxn],b[mxn];
signed main(){
scanf("%d%lld",&n,&s);
rep(i,1,n)scanf("%lld",&a[i]);
rep(i,1,n)scanf("%lld",&b[i]),b[i]+=b[i-1],mx=max(mx,b[i]);
rep(i,1,n){
while(tot&&a[i]<a[q[tot]])tot--;
l[i]=q[tot];
q[++tot]=i;
}
tot=0,q[0]=n+1;
drep(i,n,1){
while(tot&&a[i]<=a[q[tot]])tot--;
r[i]=q[tot];
q[++tot]=i;
}
rep(i,1,n){
l[i]++,r[i]--;
if(i-l[i]<r[i]-i){
rep(j,l[i],i)if(b[i]<=s-a[i]+b[j-1]){
ans+=upper_bound(b+i,b+r[i]+1,s-a[i]+b[j-1])-b-i;
}
}else{
rep(j,i,r[i])if(a[i]+b[j]-s<=b[i-1]){
ans+=i-(lower_bound(b+l[i]-1,b+i,a[i]+b[j]-s)-b);
}
}
}
cout<<ans;
return 0;
}