• Luogu1848 [USACO12OPEN]Bookshelf G


    Description

    link

    Solution

    (f_i) 表示前 (i) 本书放到书架上所得到的最小高度

    转移就挺显然的,枚举哪一段是当前书架里面的书就完了,单调队列维护和小于 (L) 的性质

    [f_{i}=min_{s_i-s_{j-1}le L} {f_j+max_{k=j+1}^ih_i} ]

    这个方程的决策点每次必然右移,如上面所说,用单调队列维护,弹队头就能做,但是还是 (n^2)

    每次新增点的时候就是对于单调队列里面的所有值进行取 (max) 操作

    弹队尾,如果当前点的 (f_i le f_{q[tail]}+calc(q[tail]+1,i)) 就弹

    (calc)(ST) 表维护区间最值

    然后发现弹队尾就错了

    其实本质上面新加入一个点就是把单调队列里面的后面的部分进行取 (max)

    然后这东西其实可以考虑用一棵线段树维护,支持区间推平成定值,维护上 (f,h) 两个量就可以了

    降低复杂度的剪枝方法:维护区间 (h) 的最大最小,推平的时候按照大小关系走一发

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define reg register 
    #define int long long
    #define For(i,a,b) for(reg int i=a;i<=b;++i) 
    namespace yspm{
        inline int read()
        {
            int res=0,f=1; char k;
            while(!isdigit(k=getchar())) if(k=='-') f=-1;
            while(isdigit(k)) res=res*10+k-'0',k=getchar();
            return res*f;
        }
        const int N=1e5+10;
        int h[N],w[N],s[N],n,l,f[N];
        deque<int> q;
        struct node{
            int sum,l,r,f,mx,mn,fl;
            #define l(p) t[p].l
            #define r(p) t[p].r
            #define f(p) t[p].f
            #define mx(p) t[p].mx
            #define mn(p) t[p].mn
            #define fl(p) t[p].fl
            #define sum(p) t[p].sum
        }t[N<<2];
       // #define min(a,b) (a<b?a:b)
       // #define max(a,b) (a>b?a:b)
        inline void push_up(int p)
        {
            mn(p)=min(mn(p<<1),mn(p<<1|1)); 
            mx(p)=max(mx(p<<1),mx(p<<1|1)); 
            sum(p)=min(sum(p<<1),sum(p<<1|1)); 
            f(p)=min(f(p<<1),f(p<<1|1));
            return ;
        }
        inline void push_down(int p)
        {
            if(!fl(p)) return ;
            mx(p<<1)=mx(p<<1|1)=mn(p<<1)=mn(p<<1|1)=fl(p);
            sum(p<<1|1)=f(p<<1|1)+fl(p);
            sum(p<<1)=f(p<<1)+fl(p);
            fl(p<<1)=fl(p<<1|1)=fl(p);
            fl(p)=0; 
            return ;
        }
        inline void build(int p,int l,int r)
        {
            l(p)=l; r(p)=r; if(l==r) return ;
            int mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r);
            return ;
        }
        inline void update(int p,int l,int r,int v)
        {
            if(mn(p)>=v) return ;
            if(l<=l(p)&&r(p)<=r)
            {
                if(mx(p)<=v) return mx(p)=mn(p)=fl(p)=v,sum(p)=v+f(p),void();
            }int mid=(l(p)+r(p))>>1; push_down(p);
            if(l<=mid) update(p<<1,l,r,v); if(r>mid) update(p<<1|1,l,r,v);
            return push_up(p);
        }
        inline int query(int p,int l,int r)
        {
            if(l<=l(p)&&r(p)<=r) return sum(p);
            int mid=(l(p)+r(p))>>1,res=1e18+10; push_down(p);
            if(l<=mid) res=min(res,query(p<<1,l,r));
            if(r>mid) res=min(res,query(p<<1|1,l,r)); 
            return push_up(p),res;   
        }
        inline void insert(int p,int pos)
        {
            if(l(p)==r(p)) return f(p)=f[pos],void();
            int mid=(l(p)+r(p))>>1; push_down(p);
            if(pos<=mid) insert(p<<1,pos); else insert(p<<1|1,pos);
            return push_up(p);
        }
        signed main()
        {
            n=read(); l=read(); build(1,0,n);
            For(i,1,n) h[i]=read(),w[i]=read(),s[i]=s[i-1]+w[i];
            q.push_back(0);
            For(i,1,n) 
            {
                while(s[i]-s[q.front()]>l) q.pop_front(); q.push_back(i);
                update(1,q.front(),i-1,h[i]); f[i]=query(1,q.front(),i-1);
                if(i!=n) insert(1,i);
            }printf("%lld
    ",f[n]);
            return 0;
        }
    }
    signed main(){return yspm::main();}
    
  • 相关阅读:
    BrowserSync,自动刷新,解放F5,去掉更新提示
    js获取手机系统语言
    块元素,行内元素,行内块区别
    原生js判断某个元素是否有指定的class名的几种方法
    如何实现调用console.log(‘good’.repeat(3))时输出goodgoodgood?
    数组如何去除重复数据,只保留一条
    Sentinel笔记-Flow流控规则
    sentinel笔记 NodeSelectorSlot,ClusterBuilderSlot
    Sentinel笔记--Slotchain
    Sentinel笔记-核心类
  • 原文地址:https://www.cnblogs.com/yspm/p/13616374.html
Copyright © 2020-2023  润新知