时间限制: 2 Sec 内存限制: 128 MB
题目描述
巨神 Ctt 被阿拉丁与神灯的故事吸引。于是,他马上去了神灯所在的山洞。Ctt 在山洞中苦苦寻找,终于找到神灯的藏身之处,他马上将神灯从玛瑙高台上取下。在那瞬间,神灯起了反应,周围的灯火全亮了。Ctt 仔细打量,发现这里是一个很大洞穴,洞穴周围有n座木门 Ctt 按照阿拉丁的步骤,轻轻擦拭神灯,洞穴周围的木门悄然打开,门后的洞穴中都是挤满洞穴的钻石。Ctt 正准备把钻石从门后的洞穴全部抱出,却听见神灯中似乎在说话:“贪婪的人没有好下场!” 后面跟着又说了m句话,第i句似乎是:“在第ai与bi座之间 (包括第ai与bi座) 的木门后的洞穴中最多只能抱出di颗钻石,否则你就会葬身于此地。”Ctt 想要知道他最多能取出多少颗钻石,但他觉得这对他来说太简单了,于是他毫不犹豫交给你,让你计算。
输入
第一行两个正整数n,m。
下面共m行,第i+1行有三个数ai,bi,di。
输出
仅一行输出一个整数表示最多取出的钻石总数。若能取出的钻石有无数多颗,则输出NO。
样例输入 Copy
【样例1】 4 3 1 3 4 2 4 5 4 4 1 【样例2】 2 2 1 1 3 2 2 5 【样例3】 4 3 1 1 2 1 2 3 4 4 3
样例输出 Copy
【样例1】 5 【样例2】 8 【样例3】 NO
提示
样例2解释:
1~3的山洞中最多可以取4个
2~4的山洞中最多可以取5个
4~4的山洞中最多可以取1个
取(1,1,2,1)为一种方案
1.先根据差分判断NO的情况
2.将m个区间根据左端点排序
3.遍历每一个点i,将区间的左端点小于等于i的区间加入优先队列,
弹出优先队列中右区间小于i的区间,同时判断区间中已经放的钻石是否满足条件,
不满足更新答案和BIT,弹出优先队列top,获取此区间已放的钻石,得到i能放钻石数,
更新BIT,更新答案,更新top区间,压入队列
注意判断是否满足条件时,多余的应该从靠右的区间中的端点删
/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
typedef long long LL;
using namespace std;
int n, m, p[100005], c[100005], b[100005];
struct node
{
int l, r, d;
bool operator <(const node &rhs)const{
return l == rhs.l ? r < rhs.r : l < rhs.l;
}
}a[1000005];
struct Node
{
int l, r, d, id;
bool operator <(const Node &rhs)const{
return d == rhs.d ? r < rhs.r : d > rhs.d;
}
};
void read(int &x){
char ch = getchar();x = 0;
for (; ch < '0' || ch > '9'; ch = getchar());
for (; ch >='0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
}
int lowbit(int x){
return x & (-x);
}
void add(int x, int w){
while(x <= n){
c[x] += w;
x += lowbit(x);
}
}
int sum(int x){
int res = 0;
while(x){
res += c[x];
x -= lowbit(x);
}
return res;
}
int main()
{
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
read(n), read(m);
for (int i = 1; i <= m; i++){
read(a[i].l), read(a[i].r), read(a[i].d);
if(a[i].l > a[i].r) swap(a[i].l, a[i].r);
p[a[i].l]++, p[a[i].r + 1]--;
}
int fg = 0;
for (int i = 1; i <= n; i++){
p[i] += p[i - 1];
if(!p[i]) {fg = 1; break;}
}
if(fg){
printf("NO\n");
return 0;
}
sort(a + 1, a + 1 + m);
priority_queue<Node> q;
int pos = 1;
for (int i = 1; i <= n; i++){
while(a[pos].l <= i && pos <= m) q.push(Node{a[pos].l, a[pos].r, a[pos].d, pos}), pos++;
while(q.size() && q.top().r < i){
int id = q.top().id, l = q.top().l;
q.pop();
int tmp = sum(a[id].r) - sum(a[id].l - 1);
if(tmp > a[id].d){
int t = min(tmp - a[id].d, b[l]);
add(l, -t);
b[l] -= t;
}
}
int id = q.top().id;
int mn = max(0, q.top().d - (sum(q.top().r) - sum(q.top().l - 1)));
add(i, mn);
q.pop();
q.push(Node{i, a[id].r, 0, id});
b[i] = mn;
// printf("%d %d\n", i, mn);
}
while(q.size()){
int id = q.top().id, l = q.top().l;
q.pop();
int tmp = sum(a[id].r) - sum(a[id].l - 1);
if(tmp > a[id].d){
int t = min(tmp - a[id].d, b[l]);
add(l, -t);
b[l] -= t;
}
}
int ans = 0;
for (int i = 1; i <= n; i++) ans += b[i];
printf("%d\n", ans);
return 0;
}
/*
4 4
1 4 10
1 4 5
1 4 6
1 4 7
6 5
1 4 10
2 6 3
2 5 2
3 4 1
4 4 1
*/