zoukankan      html  css  js  c++  java
  • 线段树区间合并优化dp——cf1197E(好)

    线段树优化dp的常见套路题,就是先按某个参数排序,然后按这个下标建立线段树,再去优化dp

    本题由于要维护两个数据:最小值和对应的方案数,所以用线段树区间合并

    /*
    dp[i]表示第i个套娃作为最内层的最小浪费空间
    dp[i]=min(dp[j])+out[i]-in[i];
    那么按照out排序后按下标建立线段树,节点维护的是二元组(区间最小值,这个最小值对应的方案数)
    求dp[i]时二分找到out[j]<=in[i]的区间[1,pos],然后线段树里查询再更新
    
    处理方案数,线段树向上合并时,只保留值最小的那个节点信息即可,如果值相同,那么将方案数合并即可
    初始值:如果一个娃外面套任何东西,那么这个娃的方案数设为1即*/
    
    
    #include<bits/stdc++.h>
    using namespace std;
    #define N 200005
    #define ll long long
    #define mod 1000000007
    
    inline ll f(ll a,ll b){
        ll res=a+b;
        if(res>mod)res-=mod;
        return res;
    }
    
    struct Node{ll out,in;}a[N];
    bool operator<(Node a,Node b){return a.in<b.in;}
    ll n,dp[N],x[N];
    
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    struct Seg {
        ll val,num;
        Seg(){}
        Seg(ll val,ll num):val(val),num(num){}
    }seg[N<<2];
    Seg merge(Seg A,Seg B){
        if(A.val<B.val)return A;
        if(A.val>B.val)return B;
        Seg res;
        res.val=A.val;
        res.num=(A.num+B.num)%mod;
        return res;
    }
    void build(int l,int r,int rt){
        seg[rt].num=0;seg[rt].val=0x3f3f3f3f3f3f3f3f;
        if(l==r)return;
        int m=l+r>>1;
        build(lson);build(rson);
    }
    void update(int pos,ll val,ll num,int l,int r,int rt){
        if(l==r){seg[rt].num=num;seg[rt].val=val;return;}
        int m=l+r>>1;
        if(pos<=m)update(pos,val,num,lson);
        else update(pos,val,num,rson);
        seg[rt]=merge(seg[rt<<1],seg[rt<<1|1]);
    }
    Seg query(int L,int R,int l,int r,int rt){
        if(L<=l && R>=r)return seg[rt];
        int m=l+r>>1;
        Seg res;
        res.val=0x3f3f3f3f3f3f3f3f;
        if(L<=m)res=merge(res,query(L,R,lson));
        if(R>m)res=merge(res,query(L,R,rson));
        return res;
    }
    
    void debug(int l,int r,int rt){
        cout<<l<<" "<<r<<" "<<seg[rt].num<<" "<<seg[rt].val<<"
    ";
        if(l==r)return;
        int m=l+r>>1;
        debug(lson);debug(rson);
    }
    
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i].out>>a[i].in;
            x[i]=a[i].in;
        }
        sort(a+1,a+1+n);sort(x+1,x+1+n);
    
        build(1,n,1);
        for(int i=n;i>=1;i--){
            int pos=lower_bound(x+1,x+1+n,a[i].out)-x;
            if(pos>n){//外面套不了娃
                update(i,a[i].in,1,1,n,1);
            }
            else {
                Seg res=query(pos,n,1,n,1);
    //cout<<res.val<<" "<<res.num<<'
    ';
                update(i,res.val-(a[i].out-a[i].in),res.num,1,n,1);
                //cout<<res.val<<" "<<res.num<<'
    ';
            }
            //debug(1,n,1);
        }
        Seg res=query(1,n,1,n,1);
        cout<<res.num;
    }
  • 相关阅读:
    深入理解JVM(二)--对象的创建
    深入理解JVM(一) -- 自动内存管理机制
    代理模式(Proxy)
    心知天气数据API 产品的高并发实践
    Jenkins 构建踩坑经历
    log4net SmtpAppender 踩坑总结
    从 ASP.NET Core 2.1 迁移到 2.2 踩坑总结
    在Windows上安装 Consul
    redis-desktop-manager 0.9.3 安装(最后一个免费版本)
    在Windows上安装Redis
  • 原文地址:https://www.cnblogs.com/zsben991126/p/11636095.html
Copyright © 2011-2022 走看看