【题意】:有一块面积为h*w的通知栏,往上面贴一些1*wi的通知上去,贴的位置总是选择可以贴的最高位置的最左端,且通知不能重叠。给出n个通知,并询问它们分别贴在第几行。
【题解】:线段树,维护线段树的区间为[1, min(h,n)],因为最坏情况也就一行贴一个,所以后面的是多余的。
因为查询和更新是同时的,所以我写在一起了。
【代码】:
1 #include "iostream"
2 #include "cstdio"
3 #include "cstring"
4 #include "algorithm"
5 #include "vector"
6 #include "queue"
7 #include "cmath"
8 #include "string"
9 #include "cctype"
10 using namespace std;
11 #define pb push_back
12 #define lc(x) (x << 1)
13 #define rc(x) (x << 1 | 1)
14 #define lowbit(x) (x & (-x))
15 #define ll long long
16 #define MAX 200050
17 int sum[MAX<<2];
18 int h, w, n;
19
20 void pushup(int p) {
21 sum[p] = max(sum[lc(p)], sum[rc(p)]);
22 }
23
24 void build(int l, int r, int p) {
25 sum[p] = w;
26 if(l == r) return;
27 int mid = (l + r) >> 1;
28 build(l, mid, lc(p));
29 build(mid + 1, r, rc(p));
30 }
31
32 int query(int L, int l, int r, int p) {
33 if(l == r) {
34 sum[p] -= L; // 找到最优位置并更新
35 return l;
36 }
37 int mid = (l + r) >> 1, ans = -1;
38 if(L <= sum[lc(p)]) ans = query(L, l, mid, lc(p));
39 else ans = query(L, mid + 1, r, rc(p));
40 pushup(p);
41 return ans;
42 }
43
44 int main() {
45 int L;
46 while(~scanf("%d%d%d", &h, &w, &n)) {
47 if(h > n) h = n;
48 build(1, h, 1);
49 for(int i = 0; i < n; i++) {
50 scanf("%d", &L);
51 if(sum[1] < L) printf("-1\n");
52 else printf("%d\n", query(L, 1, h, 1));
53 }
54 }
55 return 0;
56 }
57