Link
对于(f(l,r,x)),如果我们固定了(x),那么构造最优的(b)的方法是很简单的:
从小到大枚举(iin[0,+infty)),尽可能地让(b_{x-i},b_{x+i})大。
如果在(S)还没有放完的时候遇到了一个(pos
otin[l,r]),那么把剩下的(S)全部放到(b_{pos})就行了。
若(xin[l,mid])那么(pos=l-1),若(xin(mid,r])那么(pos=r+1)。
不难发现(xin[l,mid])时(f(l,r,x))与(r)无关,(xin(mid,r])时(f(l,r,x))与(l)无关。
因此设(f(l,r,x)=egin{cases}f(l,x)&xin[l,mid]\g(r,x)&xin(mid,r]end{cases})
预处理({a_i})的前缀和以及({ia_i})的前缀和之后可以(O(1))的求出单点(f,g)。
观察可得(f,g)满足四边形不等式。
考虑离线所有询问,对于一个形如(maxlimits_{xin[L,R]}(f ext{ or }g)(r,x))的询问,将其拆分成线段树上的(O(log n))个区间,最后对线段树的每个节点用决策单调性优化暴力枚举(x)计算即可。
时间复杂度是(O(nlog^2n)),利用基数排序可以做到(O(nlog n))。
#include<cctype>
#include<cstdio>
#include<vector>
#include<utility>
#include<algorithm>
char ibuf[1<<23|1],*iS=ibuf;
using i64=long long;
using pi=std::pair<int,int>;
const int N=200007;
int n,q;i64 s,s1[N],s2[N],ans[N];int bound[N];
std::vector<pi>trans[4*N][2];
i64 read(){i64 x=0;while(isspace(*iS))++iS;while(isdigit(*iS))(x*=10)+=*iS++&15;return x;}
i64 sum(i64*s,int l,int r){return s[r]-s[l-1];}
i64 cal(int pos,int r)
{
return r<=0? 0:pos*(sum(s1,pos-r,pos-1)-sum(s1,pos+1,pos+r))-(sum(s2,pos-r,pos-1)-sum(s2,pos+1,pos+r));
}
i64 cal(int o,int pos,int gap)
{
int f=o? 1:-1,t=o? std::min(gap+1,pos+bound[pos]+1):std::max(gap-1,pos-bound[pos]-1);
return cal(pos,f*(t-pos)-1)+f*(t-pos)*(s-(o? sum(s1,2*pos-t+1,t-1):sum(s1,t+1,2*pos-t-1)));
}
void work(int o,int l,int r,std::vector<pi>&q)
{
if(q.empty()) return ;
if(l==r){for(auto[pos,id]:q)ans[id]=std::max(ans[id],cal(o,l,pos));return;}
std::vector<pi>L,R;int lim=(int)q.size()/2,pos=0;i64 t,mx=0;
for(int i=0;i<(int)q.size();++i) if(i^lim) (i<lim? L:R).push_back(q[i]);
for(int i=l;i<=r;++i) if((t=cal(o,i,q[lim].first))>mx) mx=t,pos=i;
ans[q[lim].second]=std::max(ans[q[lim].second],mx),work(o,l,pos,L),work(o,pos,r,R);
}
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)/2)
void update(int p,int l,int r,int L,int R,int o,int pos)
{
if(L>r||l>R||L>R) return ;
if(L<=l&&r<=R) return trans[p][o].emplace_back(o? R:L,pos),void();
update(ls,l,mid,L,R,o,pos),update(rs,mid+1,r,L,R,o,pos);
}
void solve(int p,int l,int r)
{
if(l^r) solve(ls,l,mid),solve(rs,mid+1,r);
for(int i=0;i<2;++i) std::sort(trans[p][i].begin(),trans[p][i].end()),work(i,l,r,trans[p][i]);
}
#undef ls
#undef rs
int find(int pos)
{
int l=0,r=std::min(n-pos,pos-1),ans=-1;
while(l<=r) sum(s1,pos-mid,pos+mid)<s? ans=mid,l=mid+1:r=mid-1;
return ans;
}
int main()
{
fread(ibuf,1,1<<23,stdin),n=read(),s=read();
for(int i=1;i<=n;++i) {i64 x=read();s1[i]=s1[i-1]+x,s2[i]=s2[i-1]+i*x;}
q=read();
for(int i=1,l,r;i<=q;++i) l=read(),r=read(),update(1,1,n,l,mid,0,i),update(1,1,n,mid+1,r,1,i);
for(int i=1;i<=n;++i) bound[i]=find(i);
solve(1,1,n);
for(int i=1;i<=q;++i) printf("%lld
",ans[i]);
}