zoukankan      html  css  js  c++  java
  • 区间覆盖 [动态规划, 线段树]

    区间覆盖


    color{red}{正解部分}

    F[i]F[i] 表示 完全覆盖 [1,i][1, i] 的答案,

    考虑将区间按 左端点 从小到大 排序, 从左向右 枚举区间 进行状态转移, 设当前区间为 ii,
    可以初步得到状态转移方程 F[ri]=Vi ×j=li1riF[j]F[r_i] = V_i imessumlimits_{j=l_i-1}^{r_i}F[j],

    但这是错误的, 为什么 ?? 如下图所示

    橙色区间 aa 比 绿色区间 bb 先枚举, 导致了 F[rb]F[r_b] 无法转移到 F[ra]F[r_a], 这时上方的状态转移方程就出现了错误 .

    考虑怎么解决这个问题, 在上面方程中, 每个区间只能更新自己右端点 rr 对应的 F[r]F[r] 值,
    但 实际上每个区间还可以更新 [r+1,N][r+1, N]F[]F[] 值, 怎么更新 ??

    枚举到区间 ii 时, 对 j[ri+1,N]j in [r_i+1, N]F[j]F[j] 全部乘上 Vi+1V_i+1 即可, 其中 11 表示不选择 ii 区间,

    这可以使用 线段树 维护 .


    color{red}{实现部分}

    #include<bits/stdc++.h>
    #define reg register
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int mod = 1e9 + 7;
    const int maxn = 2e5 + 10;
    
    int N;
    int M;
    
    struct Intval{ int l, r, v; } A[maxn];
    
    bool cmp(Intval a, Intval b){ return a.l==b.l?a.r<b.r:a.l<b.l; }
    
    struct Segment_Tree{ 
    
            struct Node{ int l, r, v, t; } T[maxn << 3];
    
            void Build(int k, int l, int r){
                    T[k].l = l, T[k].r = r, T[k].t = 1;
                    if(l == r){ T[k].v = !l; return ; }
                    int mid = l+r >> 1;
                    Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
                    T[k].v = T[k<<1].v + T[k<<1|1].v;
            }
    
            void Push_down(int k){
                    T[k].v = 1ll*T[k].v*T[k].t % mod; 
                    T[k<<1].t = 1ll*T[k<<1].t*T[k].t % mod;
                    T[k<<1|1].t = 1ll*T[k<<1|1].t*T[k].t % mod;
                    T[k].t = 1;
            }
    
            int Query(int k, const int &ql, const int &qr){
                    int l = T[k].l, r = T[k].r;
                    if(T[k].t != 1) Push_down(k);
                    if(r < ql || l > qr) return 0;
                    if(ql <= l && r <= qr) return T[k].v; 
                    return (Query(k<<1, ql, qr) + Query(k<<1|1, ql, qr))%mod;
            }
    
            void Modify(int k, const int &ql, const int &qr, const int &x, const int &opt){
                    int l = T[k].l ,r = T[k].r;
                    if(T[k].t != 1) Push_down(k);
                    if(r < ql || l > qr) return ;
                    if(ql <= l && r <= qr){ 
                            if(opt == 1) return T[k].v = (T[k].v + x) % mod, void();
                            T[k].t = 1ll*T[k].t*x % mod; Push_down(k); return ; 
                    }
                    Modify(k<<1, ql, qr, x, opt), Modify(k<<1|1, ql, qr, x, opt);
                    T[k].v = (T[k<<1].v + T[k<<1|1].v) % mod;
            }
    
    } seg_t;
    
    int main(){
            N = read(), M = read();
            for(reg int i = 1; i <= M; i ++) A[i].l = read(), A[i].r = read(), A[i].v = read();
            std::sort(A+1, A+M+1, cmp); seg_t.Build(1, 0, N);
            for(reg int i = 1; i <= M; i ++){
                    int from = seg_t.Query(1, A[i].l-1, A[i].r);
                    from = 1ll*from*A[i].v%mod;
                    seg_t.Modify(1, A[i].r, A[i].r, from, 1);
                    if(A[i].r >= N) continue ;
                    seg_t.Modify(1, A[i].r+1, N, A[i].v+1, 2);
            }
            printf("%d
    ", seg_t.Query(1, N, N));
            return 0;
    }
    
  • 相关阅读:
    jmeter主要函数助手功用说明
    性能测试的分类
    monkey基础
    读《复盘-对过去的事情做思维演练—陈中(著)》感知
    关于postman各功能的说明及用法以及批量执行
    python接口测试-认识POST请求
    关于python3.6上传文件时报错:HTTPSConnectionPool(host='***.org', port=443): Max retries exceeded with url: /post (Caused by SSLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAIL解决办法
    [Tips] Mobaxterm添加本地python使用
    [Tips] docker run时运行shell命令
    [Tips] shell 输入输出重定向
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822437.html
Copyright © 2011-2022 走看看