P4756-Added Sequence【斜率优化】

正题

题目链接:https://www.luogu.com.cn/problem/P4756


题目大意

给出序列\(a\),设\(f(l,r)=|\sum_{i=l}^ra_i|\)

\(m\)次询问若序列\(a\)全部加上某个数\(x\),求最大的\(f(l,r)\)

\(1\leq n,m\leq 2\times 10^5\),强制在线(或许)


解题思路

求一次前缀和的话设为\(s_i\),那么\(f(l,r)=|s_r-s_l|\)。其实拆开绝对值不难发现这样就去掉了\(l,r\)的限制,答案就是\(max\{s_r\}-min\{s_l\}\)了。

然后集体加上某个数\(x\)的话,原来的\(s_i\)就变为了\(s_i+i\times x\)了。

然后就是给出\(x\)求最大和最小的\(s_i+i\times x\)。经典的斜率优化把戏。

维护一个上凸壳,一个下凸壳,然后在上面二分就好了。

时间复杂度\(O(n+m\log n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=2e5+10;
ll n,m,top,toq,f[N],s[N],t[N];
ll calc(ll x,ll i)
{return x*i+f[i];} 
signed main()
{
	scanf("%lld%lld",&n,&m);
	for(ll i=1;i<=n;i++){
		scanf("%lld",&f[i]);f[i]+=f[i-1];
		while(top&&(f[i]-f[s[top]])*(s[top]-s[top-1])>=(f[s[top]]-f[s[top-1]])*(i-s[top]))top--;s[++top]=i;
		while(toq&&(f[i]-f[t[toq]])*(t[toq]-t[toq-1])<=(f[t[toq]]-f[t[toq-1]])*(i-t[toq]))toq--;t[++toq]=i;
	}
	ll pre=0,x;
	while(m--){
		scanf("%lld",&x);x=(x+pre)%(4*n+1)-2*n;
		ll l=0,r=top-1;pre=0;
		while(l<=r){
			ll mid=(l+r)>>1;
			if(calc(x,s[mid])>calc(x,s[mid+1]))r=mid-1;
			else l=mid+1;
		}
		pre+=calc(x,s[l]);
		l=0;r=toq-1;
		while(l<=r){
			ll mid=(l+r)>>1;
			if(calc(x,t[mid])<calc(x,t[mid+1]))r=mid-1;
			else l=mid+1;
		}
		pre-=calc(x,t[l]);
		printf("%lld\n",pre);
	}
	return 0;
}
posted @ 2021-04-07 17:16  QuantAsk  阅读(93)  评论(0编辑  收藏  举报