传送门
一眼就知道是线段树区间合并,模板在这,我就不解释了。
在这道题中,
被改成了
,现在来讲讲如何实现
。
因为2操作就是
,所以自动略过。
考虑1操作:
首先在读入X后,用区间最大连续区间(即sum[1])与x进行比较,如果
,那直接输出0就可以了,否则执行
,
由于题目要求的是空区间要尽量靠左,所以查找的时候优先考虑左边,因此分三种情况:
- 1.当前线段树只有一个结点时,直接返回(递归边界,面对 的情况)
- 2.所求区间全部位于左子树时,递归左子树。判定条件就是 ,即左子树最大连续空区间长度大于 ,这样做可以让区间尽量靠左,使答案尽量优。
- 3.所求区间横跨左右子树时,直接返回位置。判定条件是 ,这种情况是在左子树无法满足要求时进行检查,相对于第4种情况要更优。返回值是 。
- 4.当前三种情况都不满足时执行,递归右子树。由于执行 前已经确认了解是存在的,所以可以直接进行递归,并可以保证一定可以找到最优解。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define max(x, y) ((x) > (y) ? (x) : (y))
struct SegTree { //和模板中0和1掉了个头
#define lc(o) o << 1
#define rc(o) o << 1 | 1
#define mid ((l + r) >> 1)
static const int MAXSIZE = 100000 + 5;
int lsum[MAXSIZE << 2], rsum[MAXSIZE << 2], sum[MAXSIZE << 2], color[MAXSIZE << 2];
void creat(int o, int l, int r, int value) {
color[o] = value;
lsum[o] = rsum[o] = sum[o] = value == 0 ? r - l + 1 : 0;
}
void pushdown(int o, int l, int r) {
if (color[o] != -1) {
creat(lc(o), l, mid, color[o]);
creat(rc(o), mid + 1, r, color[o]);
}
}
void pushup(int o, int l, int r) {
lsum[o] = color[lc(o)] == 0 ? lsum[lc(o)] + lsum[rc(o)] : lsum[lc(o)];
rsum[o] = color[rc(o)] == 0 ? rsum[lc(o)] + rsum[rc(o)] : rsum[rc(o)];
sum[o] = max(rsum[lc(o)] + lsum[rc(o)], max(sum[lc(o)], sum[rc(o)]));
if (sum[o] == 0) color[o] = 1;
else if (sum[o] == r - l + 1) color[o] = 0;
else color[o] = -1;
}
void set(int o, int l, int r, int L, int R, int value) {
if (l > R || r < L) return;
else if (L <= l && r <= R) creat(o, l, r, value);
else {
pushdown(o, l, r);
set(lc(o), l, mid, L, R, value);
set(rc(o), mid + 1, r, L, R, value);
pushup(o, l, r);
}
}
int insert(int o, int l, int r, int x) {
if (l > r) return 0;
if (l == r) return l; //情况1
pushdown(o, l, r);
if (sum[lc(o)] >= x) return insert(lc(o), l, mid, x); //情况2
else if (rsum[lc(o)] + lsum[rc(o)] >= x) return mid - rsum[lc(o)] + 1; //情况3
else return insert(rc(o), mid + 1, r, x); //情况4
}
void build(int o, int l, int r) {
if (l > r) return;
else if (l == r) creat(o, l, r, 0);
else {
build(lc(o), l, mid);
build(rc(o), mid + 1, r);
pushup(o, l, r);
}
}
}root;
int main() {
int n, m;
scanf("%d%d", &n, &m);
root.build(1, 1, n);
for (int i = 1; i <= m; i++) {
int opt, x, y;
scanf("%d", &opt);
if (opt == 1) {
scanf("%d", &x);
if (root.sum[1] < x) { //确认存在满足的解
puts("0");
continue;
}
int ret = root.insert(1, 1, n, x); //找到解
root.set(1, 1, n, ret, ret + x - 1, 1); //将找到的解得区间直接覆盖成1
printf("%d\n", ret);
}
else {
scanf("%d%d", &x, &y);
root.set(1, 1, n, x, x + y - 1, 0); //覆盖为0
}
}
return 0;
}