直接贪心,我们把线段按照右端点从小到大排序,然后一个个尝试插入即可。。。
来证明贪心的正确性:
不妨设贪心得到的答案集合为$S$,最优解的答案集合为$T$
若$S$不是最优解,那么$S \not= T$,不妨设按照右端点排序后,第一个不同的位置为$i$
则$S_i \not= T_i$,分情况讨论:
(1)$S_i$的左端点在$T_i$的右端点后,由于贪心的步骤这是不可能的
(2)$S_i$的右端点在$T_i$的右端点之前:
(2.1)$S_i$的右端点在$T_i$的左端点之前,即$S_i$、$T_i$不相交,我们发现存在$S‘ = \{S_1, S_2, ..., S_i\} \cup \{T_i, T_{i + 1}, ..., T_n\}$,且$|S‘| = |T| + 1$,矛盾
(2.2)$S_i$的右端点在$T_i$的左端点之后,即$S_i$、$T_i$相交,我们直接令$S‘ = T - \{T_i\} + \{S_i\}$,于是有$|S‘| = |T|$,即$S‘$也是最优解
故可以证明贪心的正确性
于是每次模拟的时候利用线段树即可,时间复杂度$O(mlogm + mlogn)$
1 /************************************************************** 2 Problem: 1828 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:772 ms 7 Memory:5708 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <algorithm> 12 13 using namespace std; 14 const int N = 1e5 + 5; 15 const int M = 1e5 + 5; 16 const int inf = 1e9; 17 18 int read(); 19 20 struct data { 21 int l, r; 22 23 inline void get() { 24 l = read(), r = read(); 25 } 26 inline bool operator < (const data &d) const { 27 return r < d.r; 28 } 29 } a[M]; 30 31 struct seg { 32 seg *ls, *rs; 33 int mn, tag; 34 35 #define Len (1 << 16) 36 inline void* operator new(size_t) { 37 static seg *mempool, *c; 38 if (mempool == c) 39 mempool = (c = new seg[Len]) + Len; 40 c -> ls = c -> rs = NULL, c -> mn = c -> tag = 0; 41 return c++; 42 } 43 #undef Len 44 45 inline void update() { 46 mn = min(ls -> mn, rs -> mn); 47 } 48 inline void push() { 49 ls -> tag += tag, rs -> tag += tag; 50 ls -> mn -= tag, rs -> mn -= tag; 51 tag = 0; 52 } 53 54 #define mid (l + r >> 1) 55 void build(int l, int r) { 56 if (l == r) { 57 mn = read(); 58 return; 59 } 60 (ls = new()seg) -> build(l, mid), (rs = new()seg) -> build(mid + 1, r); 61 update(); 62 } 63 64 void modify(int l, int r, int L, int R) { 65 if (L <= l && r <= R) { 66 ++tag, --mn; 67 return; 68 } 69 push(); 70 if (L <= mid) ls -> modify(l, mid, L, R); 71 if (mid < R) rs -> modify(mid + 1, r, L, R); 72 update(); 73 } 74 75 int query(int l, int r, int L, int R) { 76 if (L <= l && r <= R) return mn; 77 push(); 78 int res = inf; 79 if (L <= mid) res = min(res, ls -> query(l, mid, L, R)); 80 if (mid < R) res = min(res, rs -> query(mid + 1, r, L, R)); 81 update(); 82 return res; 83 } 84 #undef mid 85 } *T; 86 87 int n, m, ans; 88 89 int main() { 90 int i; 91 n = read(), m = read(); 92 (T = new()seg) -> build(1, n); 93 for (i = 1; i <= m; ++i) a[i].get(); 94 sort(a + 1, a + m + 1); 95 for (i = 1; i <= m; ++i) 96 if (T -> query(1, n, a[i].l, a[i].r)) 97 T -> modify(1, n, a[i].l, a[i].r), ++ans; 98 printf("%d\n", ans); 99 return 0; 100 } 101 102 inline int read() { 103 static int x; 104 static char ch; 105 x = 0, ch = getchar(); 106 while (ch < ‘0‘ || ‘9‘ < ch) 107 ch = getchar(); 108 while (‘0‘ <= ch && ch <= ‘9‘) { 109 x = x * 10 + ch - ‘0‘; 110 ch = getchar(); 111 } 112 return x; 113 }
时间: 2024-12-26 12:32:41