JZOJ 5451 Genocide

来源:互联网 发布:中南大学网络教学平台 编辑:程序博客网 时间:2024/06/06 01:05

Cenocide

Description

给出一个长度为n的序列aai表示选择第i个数的代价,设ci表示是否选择第i个数,(0为不选,1为选择),对于某种选择方案,定义总收益为
这里写图片描述
接下来有m个道具,第i个道具能够将aPi修改成Xi
对于每个道具,询问仅使用这个道具的情况下,最大的总收益为多少。

Data Constraint

这里写图片描述

Solution

考虑m=1时怎么做。
预处理出a的前缀和序列q
fi表示1~i的数已处理完的最大收益,考虑使用斜率优化。
若由j转移到i比由k转移到i更优(j < k),设仅跟j相关的项的和为Fj(Fj=fj+j(j1)2+qj),则可以得出下面的式子:FjFkjk<i
用一个单调栈维护斜率单调递减即可。
由于第i个数可以不选择,因而fi要与fi1min

现在考虑m<=3105时怎么做。
同样的,我们设gj表示j~n的数已处理完的最大收益,用上述同样的方法可以求得。
对于每一个Pi,若不选择这一个数,那么答案显然为fPi1+gPi+1
hi表示必须选择i时整个序列的最大收益,那么选择Pi这个数的收益即为hPi+aPi-Xi
现在考虑如何求出h
对于一个hxhx=max(fi+gj-qj1+qi+(ji)(ji1)2)(i < x < j

令F_i=fi+i(i+1)2+qi,Gi=gi+i(i1)2-qi1
hx=max(Fi+Gj-ij)(i < x < j

考虑分治,对于分治区间(l ,r ),考虑jmid右边,imid左边的情况来更新x在(l,mid)内的h
Wi=Fi+maxGj-i*j),那么hx每一次都可以由Wi更新到(l<i<x),做个前缀最大即可。

那现在考虑如何求出Wi,可以发现随着i的递增,决策点j越来越前,考虑对右区间维护一个斜率单调递减的单调栈(这里就不推式子来证明了,自行手推吧),随着i的增加,不断将栈顶元素退掉(当栈顶的斜率<i时便可退掉栈顶,这个自己推一下便可以发现了),如此这般便能求出对于每个i的最优决策点了。
仔细观察便能发现这样做并不能让所有的情况更新到hx,将fg对调后再翻转,a也翻转,之后再做一遍分治所有的情况便都能更新到每一个hx了。

Code

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,j,l) for(int i=j;i<=l;i++)#define fd(i,j,l) for(int i=j;i>=l;i--)using namespace std;typedef long long ll;typedef double db;const ll N=66e4,maxn=1e12;ll a[N],b[N],f[N],g[N],h[N],t[N],dd[N];int top,n,m,j,k,l,i,c; ll F[N],G[N],d[N],bb;double xl(ll a,ll b){return (F[a]-F[b])/(a-b*1.0);}double xx(ll a,ll b){return (G[a]-G[b])/(a-b*1.0);}ll max(ll a,ll b){return a>b?a:b;}void ef(int l,int r,int f){    if(l==r)return;    int k=0,mid=(l+r)/2;    fo(i,mid+1,r){        while(k-1&&xx(d[k],i)>=xx(d[k-1],d[k]))k--;        d[++k]=i;    }    t[l-1]=-maxn;    fo(i,l,mid){        while(k-1&&xx(d[k-1],d[k])<=i)k--;        t[i]=max(t[i-1],F[i]+G[d[k]]-i*d[k]);    }    if(f==0)fo(i,l,mid)h[i]=max(h[i],t[i-1]);    else fo(i,l,mid)h[n-i+1]=max(h[n-i+1],t[i-1]);    ef(l,mid,f); ef(mid+1,r,f);}int main(){    cin>>n;    fo(i,1,n)scanf("%lld",&a[i]),b[i]=b[i-1]+a[i];    int t;    d[t=1]=0;    fo(i,1,n){        while(t-1&&xl(d[t-1],d[t])<i)t--;        f[i]=max(f[i-1],f[d[t]]+(ll)(i-d[t])*(i-d[t]+1)/2-b[i]+b[d[t]]);        F[i]=f[i]+(ll)(i-1)*(ll)i/2+b[i];        while(t-1&&xl(d[t],i)>=xl(d[t-1],d[t]))t--;        d[++t]=i;    }    d[t=1]=0;    fo(i,1,n)b[i]=b[i-1]+a[n-i+1];    fo(i,1,n){        while(t-1&&xl(d[t-1],d[t])<=i)t--;        g[i]=max(g[i-1],g[d[t]]+(ll)(i-d[t])*(i-d[t]+1)/2-b[i]+b[d[t]]);        F[i]=g[i]+(ll)(i-1)*(ll)i/2+b[i];        while(t-1&&xl(d[t],i)>=xl(d[t-1],d[t]))t--;        d[++t]=i;    }    fo(i,1,n/2)swap(g[i],g[n-i+1]);    fo(i,1,n+1)dd[i]=f[i-1]+g[i+1],b[i]=b[i-1]+a[i];    fo(i,0,n+1)F[i]=f[i]+(ll)i*(i+1)/2+b[i],G[i]=g[i]+(ll)i*(i-1)/2-b[i-1];    fo(i,1,n)h[i]=-maxn;    ef(0,n+1,0);    fo(i,1,n+1)swap(f[i],g[i]),b[i]=b[i-1]+a[n-i+1];    fo(i,1,n/2)swap(f[i],f[n-i+1]),swap(g[i],g[n-i+1]);    fo(i,0,n+1)F[i]=f[i]+(ll)i*(i+1)/2+b[i],G[i]=g[i]+(ll)i*(i-1)/2-b[i-1];    ef(0,n+1,1);     cin>>m;    fo(i,1,m){        scanf("%d%lld",&c,&bb);        ll ans=max(dd[c],h[c]-(bb-a[c]));        printf("%lld\n",ans);    }}