ARC 066 F Contest with Drinks Hard
阿新 • • 發佈:2018-12-17
題目大意: 給定,求一組: 並且有組詢問,每次給定,問若將修改為時,答案是多少。每次詢問獨立,即詢問結束後修改會撤銷。 題解: 考慮不修改怎麼做,顯然是長為的一段會對答案有的貢獻,然後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(),