区间覆盖 [动态规划, 线段树]

区间覆盖


\color{red}{正解部分}

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

考虑将区间按 左端点 从小到大 排序, 从左向右 枚举区间 进行状态转移, 设当前区间为 ii,
可以初步得到状态转移方程 F[ri]=Vi ×j=li1riF[j]F[r_i] = V_i\ \times\sum\limits_{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\n", seg_t.Query(1, N, N));
        return 0;
}
posted @ 2019-10-10 17:16  XXX_Zbr  阅读(297)  评论(0编辑  收藏  举报