题目大意:
给定
,求一组
:
并且有
组询问,每次给定
,问若将
修改为
时,答案是多少。每次询问独立,即询问结束后修改会撤销。
题解:
考虑不修改怎么做,显然是长为
的一段会对答案有
的贡献,然后dp即可。这个显然可以使用斜率优化。
考虑修改怎么做,两种情况,第一种是最终不选这个位置,那么答案是
。第二种是钦定这个点选,记作
,那么答案就是
。
考虑对所有选择
这个区间的方案的收益的最大值
,那么
,考虑分治。
令solve(L,R)为处理[L,R]的子区间。
完全在某半边的递归处理。
跨mid的子区间直接做仍然是不行的,但是可以分成两部分处理:
考虑左半边的点,当选择一个区间包含这个点的时候,右端点实际上是没有用的(只是帮助取得最优值而已)。因此对于每个
,算出最优的
,然后对
取max即可。右半部分同理。
做完啦。
#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define N 300010
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
lint pre[N],suf[N],f[N],s[N],cst[N];int t[N],st[N];db A[N];
inline int getdp(lint *dp,int n)
{
rep(i,1,n) s[i]=s[i-1]+t[i];int tp=1;f[0]=0,st[1]=0;
rep(i,1,n)
{
int L=1,R=tp-1,mid=(L+R)>>1;
while(L<=R)
{
if((i+0.5)*(st[mid+1]-st[mid])>A[st[mid+1]]-A[st[mid]]) R=mid-1;
else L=mid+1;mid=(L+R)>>1;
}
dp[i]=f[st[L]]+(i-st[L])*(i-st[L]+1ll)/2-s[i]+s[st[L]],
f[i]=max(f[i-1],dp[i]),A[i]=(db)f[i]+s[i]+i/2.0*i;
while(tp>1&&(A[i]-A[st[tp]])*(st[tp]-st[tp-1])>=(A[st[tp]]-A[st[tp-1]])*(i-st[tp])) tp--;
st[++tp]=i;
}
dp[0]=0;for(int i=1;i<=n;i++) dp[i]=max(dp[i],dp[i-1]);
return 0;
}
lint dp[N];
int solve(int L,int R)
{
if(L==R) return cst[L]=pre[L-1]+suf[R+1]+1-t[R],0;
int mid=(L+R)>>1,tp;solve(L,mid),solve(mid+1,R);
tp=0;
for(int i=L-1;i<mid;i++)
{
A[i]=(db)pre[i]+s[i]+i/2.0*i;
while(tp>1&&(A[i]-A[st[tp]])*(st[tp]-st[tp-1])>=(A[st[tp]]-A[st[tp-1]])*(i-st[tp])) tp--;
st[++tp]=i;
}
for(int i=mid+1;i<=R;i++)
{
int l=1,r=tp-1,mid=(l+r)>>1;
while(l<=r)
{
if((i+0.5)*(st[mid+1]-st[mid])>A[st[mid+1]]-A[st[mid]]) r=mid-1;
else l=mid+1;mid=(l+r)>>1;
}
dp[i]=suf[i+1]+(i-st[l])*(i-st[l]+1ll)/2-s[i]+s[st[l]]+pre[st[l]];
}
cst[R]=max(cst[R],dp[R]);
for(int i=R-1;i>mid;i--) cst[i]=max(cst[i],dp[i]=max(dp[i+1],dp[i]));
tp=0;
for(int i=mid+2;i<=R+1;i++)
{
A[i]=(db)suf[i]-s[i-1]+i/2.0*i;
while(tp>1&&(A[i]-A[st[tp]])*(st[tp]-st[tp-1])>=(A[st[tp]]-A[st[tp-1]])*(i-st[tp])) tp--;
st[++tp]=i;
}
for(int i=L;i<=mid;i++)
{
int l=1,r=tp-1,mid=(l+r)>>1;
while(l<=r)
{
if((i+0.5)*(st[mid+1]-st[mid])>A[st[mid+1]]-A[st[mid]]) r=mid-1;
else l=mid+1;mid=(l+r)>>1;
}
dp[i]=pre[i-1]+(st[l]-i)*(st[l]-i+1ll)/2+s[i-1]-s[st[l]-1]+suf[st[l]];
}
cst[L]=max(cst[L],dp[L]);
for(int i=L+1;i<=mid;i++) cst[i]=max(cst[i],dp[i]=max(dp[i-1],dp[i]));
return 0;
}
int main()
{
int n=inn();rep(i,1,n) t[i]=inn();
getdp(pre,n),reverse(t+1,t+n+1);
getdp(suf,n),reverse(t+1,t+n+1);
reverse(suf+1,suf+n+1);
rep(i,1,n) s[i]=s[i-1]+t[i];
solve(1,n);
for(int q=inn(),x,y;q;q--)
x=inn(),y=inn(),printf("%lld\n",max(0ll,max(pre[x-1]+suf[x+1],cst[x]+t[x]-y)));
return 0;
}