有\(n\)个格子(\(1 \leq n \leq 30000\)),每一个格子能够种\(1\)棵树。如今给你\(h\)个要求(\(1 \leq h \leq 5000\)),格式为\(\boxed{l_i \text{ } r_i \text{ } t_i}\),表示要求格子区间\([l_i, r_i]\)中至少种\(t_i\)棵树(\(1 \leq l_i \leq r_i \leq n\),\(0 \leq t_i \leq r_i - l_i + 1\))。问你最少要种多少棵树才能知足全部要求。ios
很显然的贪心策略,每次尽量靠近\(r_i\)种树。
咱们能够用树状数组来查询一段区间内有多少棵树,而且修改每一个格子(对应种树)。
若是朴素枚举哪些格子没种树,虽然能ac,但显然不够优。咱们能够用并查集来维护对于每一个点\(i\),从\(i\)开始往\(1\)找,第\(1\)个没有种树的格子的位置\(p[i]\)。
初始化显然为\(p[i] = i\),而后对于每一个操做\(i\),咱们从\(r_i\)开始枚举没有种树的格子\(j\),显然刚开始是让\(j = p[r_i]\)。
咱们如何肯定下一个没有种树的格子呢?其实咱们能够直接使\(p[j] = p[j - 1]\),而后使\(j = p[j]\)便可,显然这是可行的。数组
#include <iostream> #include <cstdio> #include <algorithm> #define MAX_N (30000 + 5) #define MAX_H (5000 + 5) #define lowbit(x) ((x) & -(x)) using namespace std; struct Node { int l, r, t; }; inline bool cmp(Node a, Node b) { if (a.r != b.r) return a.r < b.r; return a.l < b.l; }; int n, h; Node a[MAX_H]; int s[MAX_N]; int p[MAX_N]; int GetRoot(int x) { if (x == p[x]) return x; return p[x] = GetRoot(p[x]); } void Modify(int x) { while (x <= n) ++s[x], x += lowbit(x); return; } int Query(int l, int r) { --l; int sum = 0; while (r) sum += s[r], r -= lowbit(r); while (l) sum -= s[l], l -= lowbit(l); return sum; } int main() { scanf("%d%d", &n, &h); for (int i = 1; i <= n; ++i) { p[i] = i; } for (int i = 1; i <= h; ++i) { scanf("%d%d%d", &a[i].l, &a[i].r, &a[i].t); } sort(a + 1, a + h + 1, cmp); int cnt; for (int i = 1; i <= h; ++i) { cnt = Query(a[i].l, a[i].r); for (int j = GetRoot(a[i].r); cnt < a[i].t; j = GetRoot(j)) { Modify(j); ++cnt; p[j] = GetRoot(j - 1); } } printf("%d", Query(1, n)); return 0; }