1. 程式人生 > >ARC 066 F Contest with Drinks Hard

ARC 066 F Contest with Drinks Hard

題目大意: 給定{tn}\{t_n\},求一組{xn},i[1,n],xi[0,1]\{x_n\},\forall i\in[1,n],x_i\in[0,1]max{i=1nj=in(k=ijxk)i=1nxiti}\max\left\{\sum_{i=1}^n\sum_{j=i}^n\left(\prod_{k=i}^jx_k\right)-\sum_{i=1}^nx_it_i\right\} 並且有qq組詢問,每次給定x,yx,y

,問若將txt_x修改為yy時,答案是多少。每次詢問獨立,即詢問結束後修改會撤銷。n,q3×105,1ti,y109n,q\le3\times10^5,1\le t_i,y\le10^9 題解: 考慮不修改怎麼做,顯然是長為LL的一段會對答案有L(L+1)2S(L.begin(),L.end())\frac{L(L+1)}2-S(L.begin(),L.end())的貢獻,然後dp即可。這個顯然可以使用斜率優化。 考慮修改怎麼做,兩種情況,第一種是最終不選這個位置,那麼答案是pre[x1
]+suf[x+1]pre[x-1]+suf[x+1]
。第二種是欽定這個點選,記作cst[x]cst[x],那麼答案就是cst[x]t[x]+ycst[x]-t[x]+y。 考慮對所有選擇[L,R][L,R]這個區間的方案的收益的最大值vv,那麼cst[x]=max(cst[x],v)cst[x]=\max(cst[x],v),考慮分治。 令solve(L,R)為處理[L,R]的子區間。 完全在某半邊的遞迴處理。 跨mid的子區間直接做仍然是不行的,但是可以分成兩部分處理: 考慮左半邊的點,當選擇一個區間包含這個點的時候,右端點實際上是沒有用的(只是幫助取得最優值而已)。因此對於每個L
lmidL\le l\le mid
,算出最優的mid<rRmid<r\le R,然後對[l,mid][l,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(),