题目类型 线段树
题目意思
给出最多50000个房间 最多有50000个操作
操作1 安排x个连续的空房间 (尽量安排靠前的,如果不能安排输出0) 并输出安排的第1个房间的编号
操作2 把房间 [x, x+d-1] 置空
解题方法
用 nmax[rt] 表示rt这棵线段树中最长的连续房间数量是多少
lmax[rt]表示rt这棵线段树从左到右看最长的连续房间数是多少
rmax[rt]表示rt这棵线段树从右往左看最长的连续房间数是多少
那么对于一个安排操作 如果 nmax[rt] < x 则表示无法安排 否则如果 rmax[ls] + rmax[rs] >= x 则把房间安排在区间 [mid-rmax[ls]+1, mid+x-rmax[ls]]
如果还不行就要安排在右子树, 找到安排的位置后把相应区间置为已占用
可以设一个flag数组 当 flag[rt] == 0时表示rt这棵线段树所有房间均为空 flag[rt] == 1 表示rt这棵线段树所有房间均为满
所有修改的时候修改懒惰标记即可 当下次询问或修改区间的时候pushdown即可
参考代码 - 有疑问的地方在下方留言 看到会尽快回复的
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define mid ((l+r)>>1)
const int maxn = 5e4 + 10;
int nmax[maxn*4], lmax[maxn*4], rmax[maxn*4];
int flag[maxn*4];
int n;
void build(int rt, int l, int r) {
flag[rt] = 0;
if(l == r) { nmax[rt] = lmax[rt] = rmax[rt] = 1; return ; }
build(ls, l, mid); build(rs, mid + 1, r);
lmax[rt] = rmax[rt] = nmax[rt] = nmax[ls] + nmax[rs];
}
void pushup(int rt, int l, int r) {
if(l == r) return ;
nmax[rt] = max(max(nmax[ls], nmax[rs]), rmax[ls] + lmax[rs]);
if(lmax[ls] == mid - l + 1) lmax[rt] = lmax[ls] + lmax[rs];
else lmax[rt] = lmax[ls];
if(rmax[rs] == r - mid) rmax[rt] = rmax[rs] + rmax[ls];
else rmax[rt] = rmax[rs];
}
void pushdown(int rt, int l, int r) {
if(l == r) return ;
if(flag[rt] == 0) {
nmax[ls] = lmax[ls] = rmax[ls] = mid - l + 1;
nmax[rs] = lmax[rs] = rmax[rs] = r - mid;
flag[ls] = flag[rs] = 0;
flag[rt] = -1;
}
else if(flag[rt] == 1) {
nmax[ls] = lmax[ls] = rmax[ls] = 0;
nmax[rs] = lmax[rs] = rmax[rs] = 0;
flag[ls] = flag[rs] = 1;
flag[rt] = -1;
}
}
void update(int rt, int l, int r, int L, int R, int f) {
pushdown(rt, l, r);
if(l == L && r == R) {
if(f == 0) {
nmax[rt] = lmax[rt] = rmax[rt] = r - l + 1;
flag[rt] = 0;
}
else {
nmax[rt] = lmax[rt] = rmax[rt] = 0;
flag[rt] = 1;
}
return ;
}
if(R <= mid) update(ls, l, mid, L, R, f);
else if(L > mid) update(rs, mid + 1, r,L, R, f);
else update(ls, l, mid, L, mid, f), update(rs, mid + 1, r, mid + 1, R, f);
pushup(rt, l, r);
}
int find(int rt, int l, int r, int x) {
//printf("rt = %d l = %d r = %d x = %d\n", rt, l, r, x);
pushdown(rt, l, r);
if(r - l + 1 == x && nmax[rt] == x) {
update(1, 1, n, l, r, 1);
return l;
}
if(nmax[rt] < x) return 0;
if(nmax[ls] >= x) return find(ls, l, mid, x);
else if(rmax[ls] + lmax[rs] >= x) {
//printf("rmax = %d lmax = %d\n", rmax[ls], lmax[rs]);
int L = mid - rmax[ls] + 1, R = mid + x - rmax[ls];
update(1, 1, n, L, R, 1);
return L;
}
else return find(rs, mid + 1, r, x);
pushup(rt, l, r);
}
int main() {
freopen("in", "r", stdin);
int m;
while(scanf("%d%d", &n, &m) != EOF) {
build(1, 1, n);
for( int i=0; i<m; i++ ) {
int a, b, c;
scanf("%d", &a);
if(a == 1) {
scanf("%d", &b);
int ans = find(1, 1, n, b);
printf("%d\n", ans);
}
else {
scanf("%d%d", &b, &c);
update(1, 1, n, b, b + c - 1, 0);
}
}
}
return 0;
}