现在的位置: 首页 > 综合 > 正文

POJ 3667 Hotel (线段树)

2018年01月13日 ⁄ 综合 ⁄ 共 2315字 ⁄ 字号 评论关闭

题目类型  线段树

题目意思
给出最多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;
}

抱歉!评论已关闭.