[SDOI2012]任务安排

XII.[SDOI2012]任务安排

同上一题一样,不过,这题的\(t_i\)可能有负数,这就意味着前缀和不再是单调增的!

我们不能再像前一题一样用单调队列维护了——但是因为队尾的单调性仍然存在,我们仍然可以维护上凸包。这就启发我们使用单调栈来维护斜率,并且在单调栈中二分。

我们不妨想一想,如果这个\(c\)也有可能是负数怎么办?

\(c\)是负数就意味着不再具有一个明确的凸壳——我们在两边同除时不知道\(c[j]-c[k]\)是正是负。因此,我们可以采用平衡树来支持插入斜率和查询,复杂度\(O(n\log n)\)。(该方法纯属口胡,请勿当真)

本题代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,t[300100],c[300100],f[300100],s[300100],tp;
signed main(){
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)scanf("%lld%lld",&t[i],&c[i]),t[i]+=t[i-1],c[i]+=c[i-1];
	for(int i=1;i<=n;i++){
		int L=0,R=tp;
		while(L<R){
			int mid=(L+R)>>1;
			if((f[s[mid]]-f[s[mid+1]])>=(c[s[mid]]-c[s[mid+1]])*(m+t[i]))L=mid+1;
			else R=mid;
		}
		f[i]=f[s[L]]+m*(c[n]-c[s[L]])+t[i]*(c[i]-c[s[L]]);
		while(tp&&(f[s[tp-1]]-f[s[tp]])*(c[s[tp]]-c[i])>=(f[s[tp]]-f[i])*(c[s[tp-1]]-c[s[tp]]))tp--;
		s[++tp]=i;
	}
	printf("%lld\n",f[n]);
	return 0;
}

原文地址:https://www.cnblogs.com/Troverld/p/14596868.html