您的位置:首页 > 其它

BZOJ1828 [Usaco2010 Mar]balloc 农场分配

2015-05-25 23:00 483 查看
直接贪心,我们把线段按照右端点从小到大排序,然后一个个尝试插入即可。。。

来证明贪心的正确性:

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

/**************************************************************
Problem: 1828
User: rausen
Language: C++
Result: Accepted
Time:772 ms
Memory:5708 kb
****************************************************************/

#include <cstdio>
#include <algorithm>

using namespace std;
const int N = 1e5 + 5;
const int M = 1e5 + 5;
const int inf = 1e9;

int read();

struct data {
int l, r;

inline void get() {
l = read(), r = read();
}
inline bool operator < (const data &d) const {
return r < d.r;
}
} a[M];

struct seg {
seg *ls, *rs;
int mn, tag;

#define Len (1 << 16)
inline void* operator new(size_t) {
static seg *mempool, *c;
if (mempool == c)
mempool = (c = new seg[Len]) + Len;
c -> ls = c -> rs = NULL, c -> mn = c -> tag = 0;
return c++;
}
#undef Len

inline void update() {
mn = min(ls -> mn, rs -> mn);
}
inline void push() {
ls -> tag += tag, rs -> tag += tag;
ls -> mn -= tag, rs -> mn -= tag;
tag = 0;
}

#define mid (l + r >> 1)
void build(int l, int r) {
if (l == r) {
mn = read();
return;
}
(ls = new()seg) -> build(l, mid), (rs = new()seg) -> build(mid + 1, r);
update();
}

void modify(int l, int r, int L, int R) {
if (L <= l && r <= R) {
++tag, --mn;
return;
}
push();
if (L <= mid) ls -> modify(l, mid, L, R);
if (mid < R) rs -> modify(mid + 1, r, L, R);
update();
}

int query(int l, int r, int L, int R) {
if (L <= l && r <= R) return mn;
push();
int res = inf;
if (L <= mid) res = min(res, ls -> query(l, mid, L, R));
if (mid < R) res = min(res, rs -> query(mid + 1, r, L, R));
update();
return res;
}
#undef mid
} *T;

int n, m, ans;

int main() {
int i;
n = read(), m = read();
(T = new()seg) -> build(1, n);
for (i = 1; i <= m; ++i) a[i].get();
sort(a + 1, a + m + 1);
for (i = 1; i <= m; ++i)
if (T -> query(1, n, a[i].l, a[i].r))
T -> modify(1, n, a[i].l, a[i].r), ++ans;
printf("%d\n", ans);
return 0;
}

inline int read() {
static int x;
static char ch;
x = 0, ch = getchar();
while (ch < '0' || '9' < ch)
ch = getchar();
while ('0' <= ch && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: