zoukankan      html  css  js  c++  java
  • [线段树][二分][DP]luogu P1295 [TJOI2011]书架

    题面

    https://www.luogu.com.cn/problem/P1295

    分析

    很容易想到设 $f_i$ 表示选到第 $i$ 个的最小最大值之和,则有

    $f_i=min(f_j+max(hj~hi) (j<i)$

    发现这里有一段连续的东西,然后考虑线段树。

    考虑插入一个 $h_i$ 的影响,就会使从 $i$ 向前找到的第一个 $j(h[j-1]>=h[i])$ 的 $[i,j]$ 区间 $h$ 值全部设为 $h_i$

    那么开三棵线段树,一个维护 $f$ ,一个维护 $h$ ,一个维护 $max(h_j~h_i)$

    查找 $h$ 最值时二分即可

    代码

    #include <iostream>
    #include <cstdio>
    #define lson (x<<1)
    #define rson ((x<<1)+1)
    using namespace std;
    typedef long long L;
    const L Inf=1ll<<62;
    const int N=1e5+10;
    int n,m,h[N],rev[N];
    L t[4*N],lz[4*N],f[4*N],g[4*N];
    
    void Pushdown(int x) {if (!lz[x]) return;g[lson]=f[lson]+lz[x];g[rson]=f[rson]+lz[x];lz[lson]=lz[rson]=t[lson]=t[rson]=lz[x];lz[x]=0;}
    
    void Change(int x,int l,int r,int ll,int rr,int val) {
        if (r<l) return;
        if (ll<=l&&r<=rr) {g[x]=f[x]+val;t[x]=lz[x]=val;return;}
        int mid=l+r>>1;
        Pushdown(x);
        if (ll<=mid) Change(lson,l,mid,ll,rr,val);
        if (mid<rr) Change(rson,mid+1,r,ll,rr,val);
        t[x]=max(t[lson],t[rson]);f[x]=min(f[lson],f[rson]);g[x]=min(g[lson],g[rson]);
    }
    
    void Insert(int x,int l,int r,int k,int val) {
        if (l==r) {g[x]=val+t[x];f[x]=val;return;}
        int mid=l+r>>1;
        Pushdown(x);
        if (k<=mid) Insert(lson,l,mid,k,val);
        else Insert(rson,mid+1,r,k,val);
        f[x]=min(f[lson],f[rson]);g[x]=min(g[lson],g[rson]);
    }
    
    int Get(int x,int l,int r,int ll,int rr) {
        if (ll<=l&&r<=rr) return t[x];
        int mid=l+r>>1,ans=0;
        Pushdown(x);
        if (ll<=mid) ans=Get(lson,l,mid,ll,rr);
        if (mid<rr) ans=max(ans,Get(rson,mid+1,r,ll,rr));
        return ans;
    }
    
    int Query(int l,int r,int k) {
        int mid,ans=r+1,ub=r;
        while (l<=r) {
            mid=l+r>>1;
            if (Get(1,1,n,mid,ub)<k) ans=mid,r=mid-1;
            else l=mid+1;
        }
        return ans;
    }
    
    L Query(int x,int l,int r,int ll,int rr) {
        if (ll<=l&&r<=rr) return g[x];
        int mid=l+r>>1;
        L ans=Inf;
        Pushdown(x);
        if (ll<=mid) ans=Query(lson,l,mid,ll,rr);
        if (mid<rr) ans=min(ans,Query(rson,mid+1,r,ll,rr));
        return ans;
    }
    
    int main() {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) scanf("%d",&h[i]);
        Change(1,1,n,1,1,h[1]);
        for (int i=1,s=0,j=1;i<=n;i++) {
            s+=h[i];while (s>m) s-=h[j++];
            Change(1,1,n,Query(j,i-1,h[i]),i,h[i]);
            if (i==n) return printf("%lld",Query(1,1,n,j,i)),0;
            Change(1,1,n,i+1,i+1,h[i+1]);Insert(1,1,n,i+1,Query(1,1,n,j,i));
        }
    }
    View Code
  • 相关阅读:
    python使用tcp实现一个简单的下载器
    python中的tcp
    python使用udp实现聊天器
    python网络编程-udp
    python中的eval函数
    python文件
    python模块和包
    python异常处理
    python面向对象学习(七)单例
    python面向对象学习(六)类属性、类方法、静态方法
  • 原文地址:https://www.cnblogs.com/mastervan/p/13854477.html
Copyright © 2011-2022 走看看