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;
}