BZOJ4268 : 小强的书架

首先将所有高度乘上10,设f[i]为将前i本书放入书架的最小高度,则

\[\begin{eqnarray*}
f[i]&=&\min(f[j-1]+first(j,i)+second(j,i)+W-(s[i]-s[j-1]))\\
&=&\min(f[j-1]+first(j,i)+second(j,i)+W-s[i]+s[j-1])\\
&=&\min(f[j-1]+first(j,i)+second(j,i)+s[j-1])+W-s[i]
\end{eqnarray*}\]

 

其中$1\leq j\leq i$且$s[i]-s[j-1]\leq W$。

设tmp[i][j]=f[j-1]+s[j-1]+first(j,i)+second(j,i),考虑用线段树维护tmp[i][j],如果当前要计算f[i],那么线段树的第j个叶子节点就表示tmp[i][j]。

 

为了高效维护first和second,先将所有书按高度排序,从大到小插入到set中。

假设现在插入的是第x本书,那么对于[pre(x)+1,x]内的i,first(i,x)均为a[x]。

对于[pre(pre(x))+1,pre(x)]内的i,以及[x,nxt(x)-1]内的j,second(i,j)均为a[x]。

对于[pre(x)+1,x]内的i,以及[nxt(x),nxt(nxt(x))-1]内的j,second(i,j)也均为a[x]。

于是在右端点的最小值处进行区间赋值操作即可。


时间复杂度$O(n\log n)$。

 

#include<cstdio>
#include<algorithm>
#include<set>
#define N 300010
using namespace std;
typedef long long ll;
int n,w,i,j,k,c[N],l[N],g[N],vl[N<<1],vr[N<<1],nxt[N<<1],ed;ll a[N],b[N],vw[N<<1],f;
set<int>T;set<int>::iterator it;
inline bool cmp(int x,int y){return a[x]<a[y];}
inline int get(){char c;while(!(((c=getchar())>='0')&&(c<='9')));int a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';return a;}
inline void add(int x,int l,int r,ll w){vl[++ed]=l;vr[ed]=r;vw[ed]=w;nxt[ed]=g[x];g[x]=ed;}
struct node{ll v1,v2,vc,v,t1,t2;}S[1050000];
inline void tag1(int x,ll p){
  S[x].v1=p+S[x].vc;
  S[x].v=p+S[x].v2;
  S[x].t1=p;
}
inline void tag2(int x,ll p){
  S[x].v2=p+S[x].vc;
  S[x].v=p+S[x].v1;
  S[x].t2=p;
}
inline void pb(int x){
  if(S[x].t1){
    tag1(x<<1,S[x].t1);
    tag1(x<<1|1,S[x].t1);
    S[x].t1=0;
  }
  if(S[x].t2){
    tag2(x<<1,S[x].t2);
    tag2(x<<1|1,S[x].t2);
    S[x].t2=0;
  }
}
inline void up(int x){
  S[x].v1=min(S[x<<1].v1,S[x<<1|1].v1);
  S[x].v2=min(S[x<<1].v2,S[x<<1|1].v2);
  S[x].vc=min(S[x<<1].vc,S[x<<1|1].vc);
  S[x].v=min(S[x<<1].v,S[x<<1|1].v);
}
void same1(int x,int a,int b,int c,int d,ll p){
  if(c<=a&&b<=d){tag1(x,p);return;}
  pb(x);
  int mid=(a+b)>>1;
  if(c<=mid)same1(x<<1,a,mid,c,d,p);
  if(d>mid)same1(x<<1|1,mid+1,b,c,d,p);
  up(x);
}
void same2(int x,int a,int b,int c,int d,ll p){
  if(c<=a&&b<=d){tag2(x,p);return;}
  pb(x);
  int mid=(a+b)>>1;
  if(c<=mid)same2(x<<1,a,mid,c,d,p);
  if(d>mid)same2(x<<1|1,mid+1,b,c,d,p);
  up(x);
}
void change(int x,int a,int b,int c,ll p){
  if(a==b){
    S[x].vc=p;
    S[x].v1=p+S[x].t1;
    S[x].v2=p+S[x].t2;
    S[x].v=p+S[x].t1+S[x].t2;
    return;
  }
  pb(x);
  int mid=(a+b)>>1;
  c<=mid?change(x<<1,a,mid,c,p):change(x<<1|1,mid+1,b,c,p);
  up(x);
}
ll ask(int x,int a,int b,int c,int d){
  if(c<=a&&b<=d)return S[x].v;
  pb(x);
  int mid=(a+b)>>1;ll t=1LL<<60;
  if(c<=mid)t=ask(x<<1,a,mid,c,d);
  if(d>mid)t=min(t,ask(x<<1|1,mid+1,b,c,d));
  return up(x),t;
}
int main(){
  n=get(),w=get();
  for(i=1;i<=n;i++)a[i]=10LL*get(),b[i]=b[i-1]+get(),c[i]=i;
  for(sort(c+1,c+n+1,cmp),T.insert(0),T.insert(n+1),i=n;i;i--){
    T.insert(c[i]);
    it=T.find(c[i]);
    it--,j=*it,l[c[i]]=*it+1;
    if(j)it--,add(c[i],*it+1,j,a[c[i]]);
    it=T.find(c[i]);
    it++,j=*it;
    if(j<=n)add(j,l[c[i]],c[i],a[c[i]]);
  }
  for(i=j=1;i<=n;i++){
    same1(1,1,n,l[i],i,a[i]);
    same2(1,1,n,i,i,a[i]);
    for(k=g[i];k;k=nxt[k])same2(1,1,n,vl[k],vr[k],vw[k]);
    while(b[i]-b[j-1]>w)j++;
    f=ask(1,1,n,j,i)+w-b[i];
    if(i<n)change(1,1,n,i+1,f+b[i]);
  }
  return printf("%lld.%d",f/10,f%10),0;
}

  

posted @ 2015-09-22 22:37  Claris  阅读(260)  评论(0编辑  收藏  举报