神灯 (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
*/

 

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