一、内容
二、思路
- 线段树的水题,但需要注意的是我们的区间有多大。题目给了一个h和n块板子,所以我们只需要在h 和 n中取一个最小值就是区间的大小了,因为每块板子高度是1,若h > n,那么区间取【1,n】就够了,因为每块板只放一行都只能放n行。
- 我们用c[] 数组来保存某个区间的最大剩余值的下标,这样我们查询那行能够放下这块板子,如果左边的区间能够放下这块板子,那么就往左边递归,反之则往右边递归。
- a[] 数组保存每行剩余的宽度,初始都是w。
static int query(int id, int lef, int r, int v) {
if (lef == r) {
return lef;
}
int mid = (lef + r) >> 1;
int ans = -1;
if (a[c[id << 1]] >= v) {
//向左边走 左边的最大值大于v
ans = query(id << 1, lef, mid, v);
} else if (a[c[id << 1 | 1]] >= v) {
//向右边走
ans = query(id << 1 | 1, mid + 1, r, v);
}
return ans;
}
- 更新操作,每放下一块板都要对线段树进行更新,将放置板子的一行的剩余w减去板子宽度。更新相连的区间。
static void update(int id, int lef, int r,int x, int v) {
if (lef == r) {
a[x] -= v;
return;
}
int mid = (lef + r) >> 1;
if (x <= mid) {
update(id << 1, lef, mid, x, v);
} else {
update(id << 1 | 1, mid + 1, r, x, v);
}
//进行up 更新区间的 拥有值的最大小标
if (a[c[id << 1]] >= a[c[id << 1 | 1]]) {
c[id] = c[id << 1];
} else {
c[id] = c[id << 1 | 1];
}
}
三、代码
import java.util.Scanner;
public class C_公告板 {
static int[] a = new int[200005]; //因为最多只有那么多个板子 高度不可能超过200000
static int[] c = new int[200005];
static int h, w, n, INF = 0X7f7f7f7f;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
h = sc.nextInt();
w = sc.nextInt();
n = sc.nextInt();
h = Math.min(h, n);
for (int i = 1; i <= h; i++) {
a[i] = w;
}
build(1, 1, h);
int v;
while (n-- > 0) {
v = sc.nextInt();
int x = query(1, 1, h, v);
System.out.println(x);
if (x != - 1) update(1, 1, h, x, v);
}
}
static void update(int id, int lef, int r,int x, int v) {
if (lef == r) {
a[x] -= v;
return;
}
int mid = (lef + r) >> 1;
if (x <= mid) {
update(id << 1, lef, mid, x, v);
} else {
update(id << 1 | 1, mid + 1, r, x, v);
}
//进行up 更新区间的 拥有值的最大小标
if (a[c[id << 1]] >= a[c[id << 1 | 1]]) {
c[id] = c[id << 1];
} else {
c[id] = c[id << 1 | 1];
}
}
static void build(int id, int lef, int r) {
if (lef == r) {
c[id] = lef;
return;
}
int mid = (lef + r) >> 1;
build(id << 1, lef, mid);
build(id << 1 | 1, mid + 1, r);
//up(id);
if (a[c[id << 1]] >= a[c[id << 1 | 1]]) {
c[id] = c[id << 1];
} else {
c[id] = c[id << 1 | 1];
}
}
static int query(int id, int lef, int r, int v) {
if (lef == r) {
return lef;
}
int mid = (lef + r) >> 1;
int ans = -1;
if (a[c[id << 1]] >= v) {
//向左边走 左边的最大值大于v
ans = query(id << 1, lef, mid, v);
} else if (a[c[id << 1 | 1]] >= v) {
//向右边走
ans = query(id << 1 | 1, mid + 1, r, v);
}
return ans;
}
}