ybtoj #463. 「数据结构优化 DP」序列划分

题链

分析

要求\(1\)等价于对于所有\(i<j,b[i]\leq a[j]\)必须在一段中
所以可以用数据结构维护合并
二分答案
\(f[i]\)表示前\(i\)个满足答案的最小\(a\)的和

\[f[i]=Min(f[j]+Max(a[j+1...i])),j<i且s[i]-s[j]\leq Mid \]

显然\(f[j]\)单调不降,\(Max(a[j+1..i])\)单调不增且\(Max(a[j+1..i])\)存在连续一段相同的值
考虑到对于相同的\(Max(a[j+1..i])\),j越小越好
\(\therefore\) 只需管\(a[j]=Max(a[j..i])\)和第一个j
前者可以用队列+multiset维护,后者直接指针即可

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int N=1e5+5,M=6e6+5;
int n,a[N],q[N],ls[M],rs[M],c[M],cnt,F[N][20],lg[N],rt;
ll m,f[N],s[N],zy[N],b[N];
struct A{int a;ll b; };
vector<A>V;

void add(int &p,int l,int r,int x,int k) {
	if(!p) {
		p=++cnt; ls[p]=rs[p]=0,c[p]=1e9;
	}
	if(l==r) {
		c[p]=min(c[p],k);
		return;
	}
	int mid=l+((r-l)>>1);
	if(x<=mid) add(ls[p],l,mid,x,k);
		else add(rs[p],mid+1,r,x,k);
	c[p]=min(c[ls[p]],c[rs[p]]);
}

int ask(int p,int l,int r,int x,int y) {
	if(!p) return 1e9;
	if(l==x&&r==y) return !c[p]?1e9:c[p];
	int mid=l+((r-l)>>1);
	if(y<=mid) return ask(ls[p],l,mid,x,y);
	if(x>mid) return ask(rs[p],mid+1,r,x,y);
	return min(ask(ls[p],l,mid,x,mid),ask(rs[p],mid+1,r,mid+1,y));
}

inline int Max(int l,int r) {
	int k=lg[r-l+1];
	return max(F[l][k],F[r-(1<<k)+1][k]);
}

struct B{int x; ll y; };
bool operator <(B i,B j) {
	return i.y<j.y;
}
multiset<B>S;
bool check(ll x) {
	f[1]=a[1]; int l,r,he=0; q[l=r=1]=1;
	S.clear(); S.insert((B){1,zy[1]=f[1]+a[2]});
	for(int i=2;i<=n;i++) {
		while(s[i]-s[he]>x) he++;
		f[i]=f[he]+Max(he+1,i);
		while(l<=r&&s[i]-s[q[l]]>x) {
			S.erase((B){q[l],zy[q[l]]});
			l++;
		}
		while(l<=r&&a[i]>=a[q[r]]) {
			S.erase((B){q[r],zy[q[r]]});
			r--;
		}
		if(l<=r) {
			S.erase((B){q[r],zy[q[r]]});
			zy[q[r]]=f[q[r]]+a[i];
			S.insert((B){q[r],zy[q[r]]});
		}
		if(l<=r) f[i]=min(f[i],S.begin()->y);
		if(f[i]>m) return 0;
		q[++r]=i;
		S.insert((B){i,zy[i]=f[i]+a[i+1]});
	}
	return 1;
}

int lst[N];

int main() {
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	scanf("%d%lld",&n,&m);
	for(int i=1;i<=n;i++) {
		scanf("%d%lld",&a[i],&b[i]);
	}
	c[0]=1e9;
	for(int i=1;i<=n;i++) {
		lst[i]=ask(rt,1,2e9,1,a[i]);
		if(lst[i]==1e9) lst[i]=i;
		add(rt,1,2e9,b[i],i);
	}
	for(int i=n;i;i=lst[i]-1) {
		for(int j=i-1;j>=lst[i];j--) {
			lst[i]=min(lst[i],lst[j]);
			a[i]=max(a[i],a[j]);
			b[i]+=b[j];
		}
		V.push_back((A){a[i],b[i]});
	}
	n=V.size(); 
	ll l=0,r=2e14;
	for(int i=1;i<=n;i++) {
		a[i]=V[n-i].a,s[i]=s[i-1]+V[n-i].b;
		l=max(l,V[n-i].b);
	}
	lg[0]=-1;
	for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1,F[i][0]=a[i];
	for(int j=1;j<=lg[n];j++) {
		for(int i=1;i<=n-(1<<j)+1;i++) {
			F[i][j]=max(F[i][j-1],F[i+(1<<j-1)][j-1]);
		}
	}
	ll mid,ans;
	while(l<=r) {
		mid=l+r>>1;
		if(check(mid)) ans=mid,r=mid-1;
			else  l=mid+1;
	}
	printf("%lld\n",ans);
	return 0;	
}
posted @ 2021-02-16 20:05  wwwsfff  阅读(72)  评论(0)    收藏  举报