POJ 3667 Hotel(线段树)

POJ 3667 Hotel

题目链接

题意:有n个房间,现在有两个操作

1、找到连续长度a的空房间,入住,要尽量靠左边,如果有输出最左边的房间标号,如果没有输出0

2、清空[a, a + b - 1]的房间

思路:线段树的区间合并,记录下左边连续最长和右边连续最长空房间,和每一段的最大值,这样pushup的时候就是进行区间合并,注意查询的时候由于是要尽量左,所以先查左孩子,在查横跨左右的,在查右孩子

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define lson(x) ((x<<1)+1)
#define rson(x) ((x<<1)+2)

const int N = 50005;

int n, m;

struct Node {
	int l, r, lsum, rsum, sum, sumv, lazy;
	int size() {return r - l + 1;}
	void gao(int v) {
		lazy = v;
		if (v) lsum = rsum = sum = 0;
		else lsum = rsum = sum = r - l + 1;
		sumv = l;
	}
} node[N * 4];

void pushup(int x) {
	if (node[lson(x)].lsum == node[lson(x)].size()) node[x].lsum = node[lson(x)].lsum + node[rson(x)].lsum;
	else node[x].lsum = node[lson(x)].lsum;
	if (node[rson(x)].rsum == node[rson(x)].size()) node[x].rsum = node[lson(x)].rsum + node[rson(x)].rsum;
	else node[x].rsum = node[rson(x)].rsum;
	node[x].sum = node[lson(x)].sum;
	node[x].sumv = node[lson(x)].sumv;
	if (node[x].sum < node[lson(x)].rsum + node[rson(x)].lsum) {
		node[x].sum = node[lson(x)].rsum + node[rson(x)].lsum;
		node[x].sumv = node[lson(x)].r - node[lson(x)].rsum + 1;
	}
	if (node[x].sum < node[rson(x)].sum) {
		node[x].sum = node[rson(x)].sum;
		node[x].sumv = node[rson(x)].sumv;
	}
}

void pushdown(int x) {
	if (node[x].lazy != -1) {
		node[lson(x)].gao(node[x].lazy);
		node[rson(x)].gao(node[x].lazy);
		node[x].lazy = -1;
	}
}

void build(int l, int r, int x = 0) {
	node[x].l = l; node[x].r = r; node[x].lazy = -1;
	if (l == r) {
		node[x].lsum = node[x].rsum = node[x].sum = 1;
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, lson(x));
	build(mid + 1, r, rson(x));
	pushup(x);
}

void add(int l, int r, int v, int x = 0) {
	if (node[x].l >= l && node[x].r <= r) {
		node[x].gao(v);
		return;
	}
	int mid = (node[x].l + node[x].r) / 2;
	pushdown(x);
	if (l <= mid) add(l, r, v, lson(x));
	if (r > mid) add(l, r, v, rson(x));
	pushup(x);
}

int query(int v, int x = 0) {
	if (node[x].l == node[x].r) {
		if (node[x].sum >= v) return node[x].sumv;
		return 0;
	}
	pushdown(x);
	int ans = 0;
	if (node[lson(x)].sum >= v)
		ans = query(v, lson(x));
	else if (node[lson(x)].rsum + node[rson(x)].lsum >= v) ans = node[lson(x)].r - node[lson(x)].rsum + 1;
	else if (node[rson(x)].sum >= v)
		ans = query(v, rson(x));
	pushup(x);
	return ans;
}

int main() {
	while (~scanf("%d%d", &n, &m)) {
		build(1, n);
		int op, a, b;
		while (m--) {
			scanf("%d%d", &op, &a);
			if (op == 2) {
				scanf("%d", &b);
				add(a, a + b - 1, 0);
			} else {
				int tmp = query(a);
				printf("%d\n", tmp);
				if (tmp == 0) continue;
				add(tmp, tmp + a - 1, 1);
			}
		}
	}
	return 0;
}
时间: 2024-07-29 23:12:06

POJ 3667 Hotel(线段树)的相关文章

poj 3667 Hotel - 线段树

The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Street as their v

POJ 3667 Hotel(线段树区间合并)

Description The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Stree

POJ 3667 Hotel 线段树 区间合并

题意: 1 输入a:询问是不是有连续长度为a的空房间,有的话住进最左边 2 输入a b:将[a,a+b-1]的房间清空 思路:记录区间中最长的空房间 线段树操作: update:区间替换 query:询问满足条件的最左端点 #include <cstdio> #include <iostream> #include <algorithm> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1

POJ 3667 Hotel ( 线段树区间合并 )

题目链接~~> 做题感悟:这题是接触线段树区间合并的第一题,做的很纠结. 解题思路: 注意线段树上节点代表的信息 : 每个节点需要维护 lc , rc , mc ,add ,见下图: add 为懒惰标记.假设 i 代表父亲节点编号,左儿子为  i * 2  ,右儿子为 i * 2  + 1 ,那么我们可以得到 : T [ i ] .lc 首先加上左儿子的左边的空格数,然后需要判断一下,如果左儿子的左节点占满了整个左区间时需要再加上右儿子的左边的空格数.同理 T [ i ] .rc 也可以这样得到

POJ 3667(线段树区间合并)

http://poj.org/problem?id=3667 题意:两个操作 : 1 选出靠左的长度为a的区间. 2 把从 a到a+b的区间清空. 线段树区间合并+lazy // by caonima // hehe #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cmath> using namespace std; co

POJ 1823 Hotel 线段树

题目链接 和上一题差不多....第三种操作只需要输出maxx[1]的值就可以. #include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <set> #include <string>

线段树(区间合并) POJ 3667 Hotel

题目传送门 1 /* 2 题意:输入 1 a:询问是不是有连续长度为a的空房间,有的话住进最左边 3 输入 2 a b:将[a,a+b-1]的房间清空 4 线段树(区间合并):lsum[]统计从左端点起最长连续空房间数,rsum[]类似,sum[]统计区间最长连续的空房间数, 5 它有三种情况:1.纯粹是左端点起的房间数:2.纯粹是右端点的房间数:3.当从左(右)房间起都连续时,加上另一个子节点 6 从左(右)房间起的数,sum[]再求最大值更新维护.理解没错,表达能力不足 7 详细解释:htt

POJ 2481 Cows (线段树)

Cows 题目:http://poj.org/problem?id=2481 题意:有N头牛,每只牛有一个值[S,E],如果对于牛i和牛j来说,它们的值满足下面的条件则证明牛i比牛j强壮:Si <=Sjand Ej <= Ei and Ei - Si > Ej - Sj.现在已知每一头牛的测验值,要求输出每头牛有几头牛比其强壮. 思路:将牛按照S从小到大排序,S相同按照E从大到小排序,这就保证了排在后面的牛一定不比前面的牛强壮.再按照E值(离散化后)建立一颗线段树(这里最值只有1e5,所

POJ 2299 离散化线段树

点击打开链接 Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 40827   Accepted: 14752 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by