题解 P1848 [USACO12OPEN]Bookshelf G

题解

\(f_i\) 表示前 \(i\) 本书满足条件时书架高度和的最小值。

那么对于当前位置 \(i\),满足宽度限制的最小位置 \(w\) 一定不减,可以用指针维护。

显然有 \(f_i=\min\{f_{j-1}+\max\{H_j,\cdots,H_i\}\}(w\le j\le i)\)

我们把原来的 \(H_j\) 变为 \(H_j\sim H_i\) 的最大值,显然要动态维护 \(H_w\sim H_i\) 的值,只需支持对 \(H\) 后缀取 \(\max\) 操作。

由于 \(H\) 的最大值是不增的,所以取 \(\max\) 相当于对一段后缀做区间覆盖。

线段树上二分找到当前要取 \(\max\) 的分界点,剩下的前缀不会被影响。

我们还需维护区间内 \(f_i\)\(\min\)\(f_i+H_i\)\(\min\),以及查询 \(w\sim i\) 中最小的 \(f_i+H_i\)

这都可以用线段树来维护。时间复杂度 \(O(n\log n)\)

Code

#include<cstdio>
#define LL long long
#define inf 0x3f3f3f3f3f3f3f3f
int n,l,w=1,sum=0;
int H[100008],W[100008];
LL f[100008];
struct aaa
{
	LL mnf,mnfh,laz,mnh;
}arr[400008];
inline LL max(LL a,LL b)
{
	return a>b? a:b;
}
inline LL min(LL a,LL b)
{
	return a<b? a:b;
}
inline int lson(int x)
{
	return (x<<1);
}
inline int rson(int x)
{
	return ((x<<1)|1);
}
inline void build(int k,int l,int r)
{
	if(!l)arr[k]=(aaa){0,0,0,0};
	else arr[k]=(aaa){inf,inf,0,0};
	if(l==r)return ;
	int ls=lson(k),rs=rson(k),mid=((l+r)>>1);
	build(ls,l,mid),build(rs,mid+1,r);
}
inline void modifyH(int k,int l,int r,int l1,int r1,LL d)
{
	if(l1>r1)return ;
	if(l>=l1 && r<=r1){arr[k].laz=d,arr[k].mnh=d,arr[k].mnfh=arr[k].mnf+d;return ;}
	if(arr[k].laz)arr[k].mnh=arr[k].laz,arr[k].mnfh=arr[k].mnf+arr[k].mnh;
	int ls=lson(k),rs=rson(k),mid=((l+r)>>1);
	if(arr[k].laz)
	{
		arr[ls].laz=arr[k].laz,arr[ls].mnfh=arr[ls].mnf+arr[ls].laz,arr[ls].mnh=arr[ls].laz;
		arr[rs].laz=arr[k].laz,arr[rs].mnfh=arr[rs].mnf+arr[rs].laz,arr[rs].mnh=arr[rs].laz,arr[k].laz=0;
	}
	if(r1<=mid)modifyH(ls,l,mid,l1,r1,d);
	else if(l1>mid)modifyH(rs,mid+1,r,l1,r1,d);
	else modifyH(ls,l,mid,l1,mid,d),modifyH(rs,mid+1,r,mid+1,r1,d);
	arr[k].mnfh=min(arr[ls].mnfh,arr[rs].mnfh),arr[k].mnh=min(arr[ls].mnh,arr[rs].mnh);
}
inline LL query(int k,int l,int r,int l1,int r1)
{
	if(arr[k].laz)arr[k].mnh=arr[k].laz,arr[k].mnfh=arr[k].mnf+arr[k].mnh;
	if(l>=l1 && r<=r1)return arr[k].mnfh;
	int ls=lson(k),rs=rson(k),mid=((l+r)>>1);
	if(arr[k].laz)
	{
		arr[ls].laz=arr[k].laz,arr[ls].mnfh=arr[ls].mnf+arr[ls].laz,arr[ls].mnh=arr[ls].laz;
		arr[rs].laz=arr[k].laz,arr[rs].mnfh=arr[rs].mnf+arr[rs].laz,arr[rs].mnh=arr[rs].laz,arr[k].laz=0;
	}
	if(r1<=mid)return query(ls,l,mid,l1,r1);
	if(l1>mid)return query(rs,mid+1,r,l1,r1);
	return min(query(ls,l,mid,l1,mid),query(rs,mid+1,r,mid+1,r1));
}
inline void modifyF(int k,int l,int r,int x,LL d)
{
	if(arr[k].laz)arr[k].mnh=arr[k].laz,arr[k].mnfh=arr[k].mnf+arr[k].mnh;
	if(l==r){arr[k].mnf=d,arr[k].mnfh=d+arr[k].mnh;return ;}
	int ls=lson(k),rs=rson(k),mid=((l+r)>>1);
	if(arr[k].laz)
	{
		arr[ls].laz=arr[k].laz,arr[ls].mnfh=arr[ls].mnf+arr[ls].laz,arr[ls].mnh=arr[ls].laz;
		arr[rs].laz=arr[k].laz,arr[rs].mnfh=arr[rs].mnf+arr[rs].laz,arr[rs].mnh=arr[rs].laz,arr[k].laz=0;
	}
	if(x<=mid)modifyF(ls,l,mid,x,d);else modifyF(rs,mid+1,r,x,d);
	arr[k].mnf=min(arr[ls].mnf,arr[rs].mnf),arr[k].mnfh=min(arr[ls].mnfh,arr[rs].mnfh),arr[k].mnh=max(arr[ls].mnh,arr[rs].mnh);
}
inline int find(int k,int l,int r,int l1,int r1,LL d)
{
	if(arr[k].laz)arr[k].mnh=arr[k].laz,arr[k].mnfh=arr[k].mnf+arr[k].mnh;
	if(l==r)return (d>arr[k].mnh? l:n);
	int ls=lson(k),rs=rson(k),mid=((l+r)>>1);
	if(arr[k].laz)
	{
		arr[ls].laz=arr[k].laz,arr[ls].mnfh=arr[ls].mnf+arr[ls].laz,arr[ls].mnh=arr[ls].laz;
		arr[rs].laz=arr[k].laz,arr[rs].mnfh=arr[rs].mnf+arr[rs].laz,arr[rs].mnh=arr[rs].laz,arr[k].laz=0;
	}
	if(r1>mid && d<=max(arr[ls].mnh,arr[ls].laz))return find(rs,mid+1,r,max(mid+1,l1),r1,d);
	return find(ls,l,mid,l1,min(mid,r1),d);
}
int main()
{
	scanf("%d%d",&n,&l);
	for(int i=1;i<=n;++i)scanf("%d%d",&H[i],&W[i]);
	build(1,0,n);
	for(int i=1;i<=n;++i)
	{
		for(sum+=W[i];sum>l;++w)sum-=W[w];
		modifyH(1,0,n,find(1,0,n,0,i-1,H[i]),i-1,H[i]),f[i]=query(1,0,n,w-1,i-1),modifyF(1,0,n,i,f[i]);
	}
	printf("%lld",f[n]);
	return 0;
}
posted @ 2021-07-05 19:44  18Michael  阅读(64)  评论(0编辑  收藏  举报