设 表示 完全覆盖 的答案,
考虑将区间按 左端点 从小到大 排序, 从左向右 枚举区间 进行状态转移, 设当前区间为 ,
可以初步得到状态转移方程 ,
但这是错误的, 为什么 如下图所示
橙色区间 比 绿色区间 先枚举, 导致了 无法转移到 , 这时上方的状态转移方程就出现了错误 .
考虑怎么解决这个问题, 在上面方程中, 每个区间只能更新自己右端点 对应的 值,
但 实际上每个区间还可以更新 的 值, 怎么更新
枚举到区间 时, 对 的 全部乘上 即可, 其中 表示不选择 区间,
这可以使用 线段树 维护 .
#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;
}