直接贪心,我们把线段按照右端点从小到大排序,然后一个个尝试插入即可。。。

来证明贪心的正确性:

不妨设贪心得到的答案集合为$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 }
View Code

 

posted on 2015-05-25 23:00  Xs酱~  阅读(498)  评论(0编辑  收藏  举报