ARC 066 F Contest with Drinks Hard - 斜率优化dp - 分治

题目大意:
给定 { t n } \{t_n\} ,求一组 { x n } , i [ 1 , n ] , x i [ 0 , 1 ] \{x_n\},\forall i\in[1,n],x_i\in[0,1] max { i = 1 n j = i n ( k = i j x k ) i = 1 n x i t i } \max\left\{\sum_{i=1}^n\sum_{j=i}^n\left(\prod_{k=i}^jx_k\right)-\sum_{i=1}^nx_it_i\right\}
并且有 q q 组询问,每次给定 x , y x,y ,问若将 t x t_x 修改为 y y 时,答案是多少。每次询问独立,即询问结束后修改会撤销。 n , q 3 × 1 0 5 , 1 t i , y 1 0 9 n,q\le3\times10^5,1\le t_i,y\le10^9
题解:
考虑不修改怎么做,显然是长为 L L 的一段会对答案有 L ( L + 1 ) 2 S ( L . b e g i n ( ) , L . e n d ( ) ) \frac{L(L+1)}2-S(L.begin(),L.end()) 的贡献,然后dp即可。这个显然可以使用斜率优化。
考虑修改怎么做,两种情况,第一种是最终不选这个位置,那么答案是 p r e [ x 1 ] + s u f [ x + 1 ] pre[x-1]+suf[x+1] 。第二种是钦定这个点选,记作 c s t [ x ] cst[x] ,那么答案就是 c s t [ x ] t [ x ] + y cst[x]-t[x]+y
考虑对所有选择 [ L , R ] [L,R] 这个区间的方案的收益的最大值 v v ,那么 c s t [ x ] = max ( c s t [ x ] , v ) cst[x]=\max(cst[x],v) ,考虑分治。
令solve(L,R)为处理[L,R]的子区间。
完全在某半边的递归处理。
跨mid的子区间直接做仍然是不行的,但是可以分成两部分处理:
考虑左半边的点,当选择一个区间包含这个点的时候,右端点实际上是没有用的(只是帮助取得最优值而已)。因此对于每个 L l m i d L\le l\le mid ,算出最优的 m i d < r R mid<r\le R ,然后对 [ l , m i d ] [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(),printf("%lld\n",max(0ll,max(pre[x-1]+suf[x+1],cst[x]+t[x]-y)));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/83420975