这里一个网格状的房间,一共有nn列,但是有正无穷的行。
小AA一开始在第00行,可以任意选择所在的列。现在他每次可以向下走一格(行号+1),或者向右下走一格(行列同时+1)。
在行走过程中,小AA需要不断消耗体力。具体来说,每经过一个第ii列的格子,需要消耗AiAi的体力。
现在小AA会一共行走mm次,每次会给出目标坐标第xx行第yy列,请你求出走到那所消耗的最小体力。
输入格式
第一行一共两个整数,nn和mm。
第二行一共nn个整数,AiAi。
接下来mm行,每行两个整数,xx和yy。
输出格式
mm行,每行一个整数,表示每个询问的最小体力。
样例
Input
6 4
2 2 3 4 3 4
4 5
3 4
3 4
2 3
Output
12
9
9
5
数据规模与约定
对于20%20%的数据,满足n,m≤100n,m≤100;
对于60%60%的数据,满足n,m≤1000n,m≤1000;
对于100%100%的数据,满足n,m≤105,1≤x≤y≤n,0≤Ai≤10000n,m≤105,1≤x≤y≤n,0≤Ai≤10000;
时间限制:1s
空间限制:512MB
考虑暴力,可以发现我们消耗的能量是我们选择的区间和+(x-y+i)*min(ai),即sumy-sumi+(x-(y-i))*ai=(x-y)*ai+(i *ai-sumi)+sumy
发现这可以用单调队列维护
线段树每个区间维护一个单调队列。
#include
#define ll long long
using namespace std;
const int N=1e5+77;
int n,q,X,ans,aa[N],sum[N],K[N],B[N],Q[N*30],c[N],bot,a[N];
struct Node
{
int l,r,st,en;
}T[N<<2];
bool cmp(int x,int y)
{
return K[x]>K[y]||(K[x]==K[y]&&B[x]<B[y]);
}
double pos(int x,int y)
{
return (double)(B[y]-B[x]) / (K[x]-K[y]);
}
void baoli()
{
scanf("%d%d",&n,&q);
for(int i=1; i<=n; i++) scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
ll aii=0x3f3f3f3f,yjy=0x3f3f3f3f;
for(int i=y; i>=max(y-x,1); i--)
{
aii=min(aii,1ll*a[i]);
yjy=min(yjy,aii*(x-y+i-1)+sum[y]-sum[i-1]);
}
printf("%lld\n",yjy);
}
}
void build(int i,int l,int r)
{
T[i].l=l;
T[i].r=r;
int t=0,now=T[i].st=bot+1;
for(int j=l; j<=r; j++)
c[++t]=j;
sort(c+1,c+t+1,cmp);
Q[++bot]=c[1];
for(int j=2; j<=t; j++)
if(K[c[j]]<K[c[j-1]])
{
while(bot>now&&pos(Q[bot-1],Q[bot])>pos(Q[bot],c[j]))
bot--;
Q[++bot]=c[j];
}
T[i].en=bot;
if(l==r)
return;
int M=l+r >> 1;
build(i<<1,l,M);
build(i<<1|1,M+1,r);
}
void query(int l,int r)
{
while(l<r)
{
int M=(l+r >> 1)+1;
if(X >= pos(Q[M-1],Q[M]))
l=M;
else
r=M-1;
}
ans=min(ans,K[Q[l]]*X+B[Q[l]]);
}
void query(int i,int l,int r)
{
if(l<=T[i].l&&T[i].r<=r)
{
query(T[i].st,T[i].en);
return;
}
int M=T[i].l+T[i].r >> 1;
if(l<=M)
query(i<<1,l,r);
if(r>M)
query(i<<1|1,l,r);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1; i<=n; i++)
scanf("%d",&aa[i]),sum[i]=sum[i-1]+aa[i],K[i]=aa[i],B[i]=aa[i]*i-sum[i];
build(1,1,n);
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
ans=0x3f3f3f3f;
X=x-y;
query(1,y-x+1,y);
printf("%d\n",ans+sum[y]);
}
}