题意:
题目链接
给出一个长度为n(n<=5e5)的序列A,给出q(q<=5e5)个询问
每个询问包含L,R
要求在[L,R]中选择a,b,c三个数满足a<b<c且b-a<=c-b
求在满足条件的情况下,(A_a+A_b+A_c)的最大值
题解:
考虑对于一组最优解(a,b,c)
对于任意x满足a<x<b
如果有(A_x>A_a),那么(x,b,c)显然更优,矛盾
如果有(A_x>A_b),那么(a,x,c)显然更优,矛盾
因此(A_x<=min(A_a,A_b))
那么我们考虑用单调栈维护这样的(a,b)数对(个数是(O(n))的)
然后每次都用后缀和计算(A_c)的最大值
总复杂度(O(n^2))
考虑如何进一步优化
我们记(f_i)表示c=i时(A_a+A_b+A_c)的最大值
离线下所有的询问,然后倒序扫描
枚举到a时,处理所有的二元组(a,b)
对于所有的i满足(i>=2b-a),修改(f_i=max(f_i,A_a+A_b+A_i))
那么对于区间[L,R]答案就是(max_{i=L}^R f_i)
线段树维护一下就好了
code:
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
typedef pair<int,int> pii;
typedef long long ll;
#define fi first
#define se second
int n,sta[N],top,m;
ll ans[N],mx[N<<2],a[N],tag[N<<2],tmp[N<<2];
vector<int>pos[N];
vector<pii>q[N];
inline int read()
{
int s=0,w=1; char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
return s*w;
}
#define lc (rt<<1)
#define rc (rt<<1|1)
inline void mt(int rt,ll u)
{
mx[rt]=max(mx[rt],u+tmp[rt]);
tag[rt]=max(tag[rt],u);
}
inline void down(int rt)
{
if(!tag[rt])return;
mt(lc,tag[rt]),mt(rc,tag[rt]);
tag[rt]=0;
}
inline void up(int rt){mx[rt]=max(mx[lc],mx[rc]);}
void build(int rt,int l,int r)
{
if(l==r){tmp[rt]=a[l];return;}
int mid=l+r>>1;
build(lc,l,mid);build(rc,mid+1,r);
tmp[rt]=max(tmp[lc],tmp[rc]);
}
void update(int rt,int l,int r,ll u,int bl=1,int br=n)
{
if(l<=bl&&br<=r){mt(rt,u);return;}
down(rt);
int mid=bl+br>>1;
if(l<=mid)update(lc,l,r,u,bl,mid);
if(mid<r)update(rc,l,r,u,mid+1,br);
up(rt);
}
ll query(int rt,int l,int r,int bl=1,int br=n)
{
if(l<=bl&&br<=r)return mx[rt];
down(rt);
int mid=bl+br>>1;ll res=0;
if(l<=mid)res=max(res,query(lc,l,r,bl,mid));
if(mid<r)res=max(res,query(rc,l,r,mid+1,br));
up(rt);
return res;
}
#undef lc
#undef rc
int main()
{
n=read();
for(int i=1;i<=n;++i)a[i]=1ll*read();
for(int i=1;i<=n;++i)
{
while(top&&a[sta[top]]<a[i])pos[sta[top--]].push_back(i);
if(top)pos[sta[top]].push_back(i);sta[++top]=i;
}
build(1,1,n);
m=read();
for(int i=1;i<=m;++i)
{
int l=read(),r=read();
q[l].push_back(make_pair(r,i));
}
for(int i=n;i>=1;--i)
{
for(vector<int>::iterator it=pos[i].begin();it!=pos[i].end();it++)
if(*it+*it-i<=n)update(1,*it+*it-i,n,a[i]+a[*it]);
for(vector<pii>::iterator it=q[i].begin();it!=q[i].end();it++)
ans[(*it).se]=query(1,i,(*it).fi);
//脑抽了,vector直接像数组那样遍历更方便
}
for(int i=1;i<=m;++i)printf("%lld
",ans[i]);
return 0;
}