題解 P1848 [USACO12OPEN]Bookshelf G
阿新 • • 發佈:2021-07-05
題解
設 \(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; }