時間限制: 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
*/