题目链接:点击打开链接
思路:把所有约束按照右端点排序。这样每一个前面的约束区间[l1,r1],与后面的一个约束区间[l2,r2]的交,一定为[max(l1 ,l2 ),r1]。对于排序后的区间依次满足约束,假设当前枚举到的约束还没有满足,就不断把对应区间中最右端的0改为1,这些过程可以用线段树维护来完成。时间复杂度O((n + m)logn)。
// 监视任务 运行/限制:898ms/2000ms
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define lson le,mid,root<<1
#define rson mid+1,rig,root<<1|1
struct node {
int l, r, k;
bool operator<(const node& b)const {
return r < b.r;
}
}a[1000005];
int sum[500005 << 2];
int book[500005];
void pushUp(int root) {
sum[root] = sum[root << 1] + sum[root << 1 | 1];
}
void build(int le, int rig, int root) {
if (le == rig) {
sum[root] = 0;
return;
}
int mid = (le + rig) >> 1;
build(lson);
build(rson);
pushUp(root);
}
int query(int l, int r, int le, int rig, int root) {
if (l <= le && r >= rig) {
return sum[root];
}
int re = 0;
int mid = (le + rig) >> 1;
if (l <= mid) {
re += query(l, r, lson);
}
if (r > mid) {
re += query(l, r, rson);
}
return re;
}
void update(int pos, int le, int rig, int root) {
if (le == rig) {
sum[root] = 1;
return;
}
int mid = (le + rig) >> 1;
if (pos <= mid) {
update(pos, lson);
}
else {
update(pos, rson);
}
pushUp(root);
}
int main(){
int n, m, ans;
while (scanf("%d%d", &n, &m) != EOF) {
ans = 0;
memset(book, 0, sizeof(book));
for (int i = 0; i < m; i++) {
scanf("%d%d%d",&a[i].l, &a[i].r, &a[i].k);
}
build(1, n, 1);
sort(a, a + m);
for (int i = 0; i < m; i++) {
int pos = a[i].r;//区间右边界
int cnt = query(a[i].l,a[i].r, 1, n, 1);//查询该区间已经被防卫的点的数量
while (cnt < a[i].k) {
while (book[pos]) pos--;//从右向左找位置加防卫
book[pos] = 1;
update(pos, 1, n, 1);
ans++;
cnt++;
}
}
printf("%d\n", ans);
}
return 0;
}