问题描述
有一个$h * w$的矩形,现在要在上边放置$n$个东西。东西的宽度为$w_i$。
放东西的原则是:
1.尽可能的在上层
2.尽可能放在左边
你要输出的是这$n$个东西在这个矩形的第几行。
输入
$n, w, n$ 其中 $1 <= h, w <= 10^9, 1 <= n <= 200,000$
下边又有$n$行数据,表示$w_i$, $1 <= w_i <= 10^9$
思路
我们可以画一下样例 ,如图所示
我们可以发现,对该矩形我们需要:
我们先不考虑全题,我们考虑局部。
对于区间$[l, r]$来说,左半边的最大值是$l_x$, 右半边的最大值是$r_x$。
- 如果一边是$>= w$,另一边不符合。我们直接选择即可。
- 如果两边都$<w$,那么我们可以直接输出$-1$。
- 如果两边都$>= w$,我们左右都可以放置,这样我们可以根据题目中的要求,选择左边。
简而言之,我们对于每一个$w_i$来说,都尽可能选择$h$较小且优先选择左边的。
询问的数据在$2*10^5$,$h$和$w$的范围是$1 <= h, w <= 10^9$,我们可以用线段树来维护这个矩形中每一行剩余的最大面积,对于每一个$w_i$,我们找到一个正确的行给它,并且用$ans$数组来记录所对应的行数。
我们可以搜改一体,找到之后,就修改这一行的最大面积(即结点存储的值),并返回其位置。
现在就剩下最后一个问题了 对于数组空间 我们应该取什么样的值……
是根据$h$的范围,还是根据$n$的范围
我们看一下两个变量的范围 :
显然直接根据n的范围开数组一定会爆,我们考虑一下,
如果每行一个$w_i$,这样有可能高度达到$n$。那么最多也只有$2 * 10^5$个。
所以我们再开线段树空间的时候,最大开四倍的$n$即可。
我们建立的时候,直接比较$max(h, n)$即可。根据大的那一个建树。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| #include <bits/stdc++.h> #define ll long long #define IOS {ios::sync_with_stdio(false);cin.tie(0);} using namespace std; const int maxn = 200000 + 2; ll h, w, n; ll row; ll d[maxn << 2], ans[maxn]; void push_up(int rt) { d[rt] = max(d[rt << 1], d[rt << 1 | 1]); } void build(int l, int r, int rt) { if(l == r) { d[rt] = w; return ; } int m = (l + r) >> 1; build(l, m, rt << 1); build(m + 1, r, rt << 1 | 1); push_up(rt); } void update(int v, int l, int r, int rt) { if(l == r) { if(d[rt] >= v) { d[rt] -= v; ans[row++] = l; } else { ans[row++] = -1; } return ; } int m = (l + r) >> 1; if(d[rt] >= v) { if(d[rt << 1] >= v) update(v, l, m, rt << 1); else update(v, m + 1, r, rt << 1 | 1); } else { ans[row++] = -1; return ; } push_up(rt); } int main(void) { IOS while(cin >> h >> w >> n) { memset(d, 0, sizeof(d)); memset(ans, 0, sizeof(ans)); row = 0; if(h > n) h = n; build(1, h, 1); for(int i = 1; i <= n; i++) { int x; cin >> x; update(x, 1, h, 1); } for(int i = 0; i < row; i++) cout << ans[i] << endl; } return 0; }
|
注意点
单点更新时变量的变化逻辑关系
搜改一体的具体操作细节见代码
提供一个构造特例:
input:
output: