神燈 (lamp)(BIT+優先隊列)

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章