建筑抢修 BZOJ 1029
建筑抢修
【问题描述】
小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者。但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏。现在的情况是:T部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间。同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑。如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了。你的任务是帮小刚合理的制订一个修理顺序,以抢修尽可能多的建筑。
【输入格式】
第一行是一个整数N接下来N行每行两个整数T1,T2描述一个建筑:修理这个建筑需要T1秒,如果在T2秒之内还没有修理完成,这个建筑就报废了。
【输出格式】
输出一个整数S,表示最多可以抢修S个建筑.
【样例输入】
4
100 200
200 1300
1000 1250
2000 3200
【样例输出】
3
【数据范围】
N < 150,000,T1 < T2 < maxlongint
题解:
先按T2排序,按顺序枚举
贪心考虑,如果能在T2内维修好就加入左偏树(大根堆)
否则考虑与堆顶的关系
如果不维修堆顶而维修当前建筑使用时间更少,就将堆顶弹出加入当前建筑
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdlib>
5 #include<cstdio>
6 #include<cmath>
7 using namespace std;
8 inline int Get()
9 {
10 int x;
11 char c;
12 while((c = getchar()) < '0' || c > '9');
13 x = c - '0';
14 while((c = getchar()) >= '0' && c <= '9') x = x * 10 + c - '0';
15 return x;
16 }
17 const int me = 1000233;
18 struct building
19 {
20 int x, y;
21 }a[me];
22 int n, rt, num;
23 int dis[me], lc[me], rc[me];
24 inline bool rule(const building &a, const building &b)
25 {
26 if(a.y != b.y) return a.y < b.y;
27 return a.x < b.x;
28 }
29 int Marge(int x, int y)
30 {
31 if(!x) return y;
32 if(!y) return x;
33 if(a[x].x < a[y].x) swap(x, y);
34 rc[x] = Marge(rc[x], y);
35 if(dis[lc[x]] < dis[rc[x]]) swap(lc[x], rc[x]);
36 if(!rc[x]) dis[x] = 0;
37 else dis[x] = dis[rc[x]] + 1;
38 return x;
39 }
40 int main()
41 {
42 n = Get();
43 for(int i = 1; i <= n; ++i)
44 {
45 a[i].x = Get();
46 a[i].y = Get();
47 }
48 sort(a + 1, a + 1 + n, rule);
49 int ti = 0;
50 for(int i = 1; i <= n; ++i)
51 {
52 if(ti + a[i].x <= a[i].y)
53 {
54 rt = Marge(rt, i);
55 ti += a[i].x;
56 ++num;
57 }
58 else
59 {
60 if(!rt) continue;
61 int c = ti - a[rt].x + a[i].x;
62 if(c <= a[i].y && a[i].x < a[rt].x)
63 {
64 int a = lc[rt], b = rc[rt];
65 rt = Marge(a, b);
66 rt = Marge(rt, i);
67 ti = c;
68 }
69 }
70 }
71 printf("%d", num);
72 }