题目链接:https://vijos.org/d/ybttg/p/5c24aef1f41362c9e1912630
时间限制:1000 ms 内存限制:512 MiB
题目描述
某条街被划为 n n n条路段,这 n n n条路段依次编号为 1 … n 1\dots n 1…n。每个路段最多可以种一棵树。现在居民们给出了 h h h组建议,每组建议包含三个整数 b , e , t b,e,t b,e,t,表示居民希望在路段 b b b到 e e e之间至少要种 t t t棵树。这些建议所给路段的区间可以交叉。请问:如果要满足所有居民的建议,至少要种多少棵树。
输入格式
第一行为 n n n,表示路段数。
第二行为 h h h,表示建议数。
下面 h h h行描述一条建议: b , e , t b, e, t b,e,t,用一个空格分隔。
输出格式
输出只有一个数,为满足所有居民的建议,所需要种树的最少数量。
样例输入
9
4
1 4 2
4 6 2
8 9 2
3 5 2
样例输出
5
限制与提示
30 % 30\% 30%的数据满足 0 < n ≤ 1000 , 0 < h ≤ 500 ; 0<n\le 1000,0<h\le 500; 0<n≤1000,0<h≤500;
100 % 100\% 100%的数据满足 0 < n ≤ 3 × 1 0 4 , h ≤ 5000 , 0 < b ≤ e ≤ 3 × 1 0 4 , t ≤ e − b + 1 0<n\le 3 \times 10^4,h \le 5000,0<b \le e\le 3\times 10^4,t\le e-b+1 0<n≤3×104,h≤5000,0<b≤e≤3×104,t≤e−b+1。
解题思路
题意: n个居民希望在路段
b
i
b_i
bi到
e
i
e_i
ei之间至少要种
t
i
t_i
ti棵树,区间可以交叉。求满足所有居民的建议,至少要种多少棵树。
思路: 贪心。先按结束位置从小到大排序,对每个区间依次处理,从前到后扫描这个区间,统计已选点的个数,若已选点的个数满足要求的点数,则跳过,否则从该区间由后向前扫描,添加缺少的覆盖点。
Accepted Code:
/*
* @Author: lzyws739307453
* @Language: C++
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3e4 + 5;
const int MAXM = 5e3 + 5;
struct edge {
int s, e, t;
bool operator < (const edge &s) const {
return e < s.e;
}
}p[MAXM];
bool vis[MAXN];
int main() {
int n, m, ans = 0;
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++)
scanf("%d%d%d", &p[i].s, &p[i].e, &p[i].t);
sort(p, p + m);
for (int i = 0; i < m; i++) {
int cnt = 0;
for (int j = p[i].s; j <= p[i].e; j++)
if (vis[j])
cnt++;
if (cnt >= p[i].t) continue;
for (int j = p[i].e; j >= p[i].s && cnt < p[i].t; j--) {
if (!vis[j]) {
cnt++, ans++;
vis[j] = true;
}
}
}
printf("%d\n", ans);
return 0;
}