PKU 3667 Hotel (线段树,区间合并,最长连续区间)

题意:宾馆有N个房间(1~N),M个操作,a=1,输入b,表示N间房是否有连续的b间房。有输出最左边的房编号

没有输出0。a=2,输入b,c表示房间b到c清空。

模仿了大神的代码,敲了一遍,有些地方还要深入了解。

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <queue>
#include <math.h>
#define M 50001
#define eps 1e-6
#define LL long long
using namespace std;

struct node
{
	int left,right;
	int lsum,rsum,msum;
	int lazy;
}tree[M*3];

void push_up(int id)
{
	int ll=tree[id<<1].right-tree[id<<1].left+1;
	int rr=tree[id<<1|1].right-tree[id<<1|1].left+1;
	tree[id].lsum=tree[id<<1].lsum;
	if(tree[id<<1].lsum==ll)
		tree[id].lsum+=tree[id<<1|1].lsum;
	tree[id].rsum=tree[id<<1|1].rsum;
	if(tree[id].rsum==rr)
		tree[id].rsum+=tree[id<<1].rsum;
	tree[id].msum = max(max(tree[id<<1].msum,tree[id<<1|1].msum),tree[id<<1].rsum+tree[id<<1|1].lsum);
}
void push_down(int id)
{
	if(tree[id].lazy!=-1)
	{
		int ll=tree[id<<1].right-tree[id<<1].left+1;
		int rr=tree[id<<1|1].right-tree[id<<1|1].left+1;
		tree[id<<1].lazy=tree[id<<1|1].lazy=tree[id].lazy;
		tree[id].lazy=-1;
		tree[id<<1].rsum = tree[id<<1].lsum = tree[id<<1].msum = tree[id<<1].lazy ?

0:ll;
        tree[id<<1|1].rsum = tree[id<<1|1].lsum = tree[id<<1|1].msum = tree[id<<1|1].lazy ?0:rr;
	}
}
void build(int id,int l,int r)
{
	tree[id].left=l;tree[id].right=r;
	tree[id].lsum=tree[id].rsum=tree[id].msum=(r-l+1);
	tree[id].lazy=-1;
	if(l==r)
		return ;
	int mid=(l+r)/2;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	//push_up(id);
}

void update(int id,int l,int r,int c)
{
	if(tree[id].left==l&&tree[id].right==r)
	{
		tree[id].lsum=tree[id].rsum=tree[id].msum=c?0:(r-l+1);
		tree[id].lazy=c;
		return ;
	}
	push_down(id);
	int mid=(tree[id].left+tree[id].right)/2;
	if(r<=mid) update(id<<1,l,r,c);
	else if(l>mid) update(id<<1|1,l,r,c);
	else
	{
		update(id<<1,l,mid,c);
		update(id<<1|1,mid+1,r,c);
	}
	push_up(id);
}
int query(int id,int v)
{
	if(tree[id].left==tree[id].right) return tree[id].left;
	push_down(id);
	int mid=(tree[id].left+tree[id].right)/2;
	if(tree[id<<1].msum>=v)//假设左子树的最大连续空>=需求量。那么直接进入左子树,=也去左子树的原因是题目要求的最左
		return query(id<<1,v);
	else if(tree[id<<1].rsum+tree[id<<1|1].lsum>=v)//左子树的连续右+右子树的连续左>=w,说明找到了能够直接求出
		return mid-tree[id<<1].rsum+1;
	return query(id<<1|1,v);
}

int main()
{

	int n,m;
	while(~scanf("%d%d",&n,&m))
	{
		int a,b,c;
		build(1,1,n);
		while(m--)
		{
			scanf("%d",&a);
			if(a==1)
			{
				scanf("%d",&c);
				if(tree[1].msum<c) printf("0\n");//根节点的最大连续空间不够
				else
				{
					int p=query(1,c);
					printf("%d\n",p);
					update(1,p,p+c-1,1);//把这段更新为被覆盖
				}
			}
			else
			{
				scanf("%d%d",&b,&c);
				update(1,b,b+c-1,0);//把这段更新为未被覆盖
			}
		}
	}
	return 0;
}

/*
10 6
1 3
1 3
1 3
1 3
2 5 5
1 6
*/
时间: 2024-10-14 02:44:14

PKU 3667 Hotel (线段树,区间合并,最长连续区间)的相关文章

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 ( 线段树区间合并 )

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

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(线段树区间合并)

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 3667 Hotel 【线段树 区间合并 + Lazy-tag】

Hotel Time Limit: 3000MS Memory Limit: 65536K 链接:POJ 3667   Description The cows are journeying north to ThunderBay in Canada to gain cultural enrichment and enjoy a vacation on the sunnyshores of Lake Superior. Bessie, ever the competent travel agen

线段树(区间合并) 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 3667——hotel——————【线段树区间合并】

Hotel Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 13124   Accepted: 5664 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

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

Language: Default Hotel Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12417   Accepted: 5346 Description The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lak

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

题意: 有一个线段,从1到n,下面m个操作,操作分两个类型,以1开头的是查询操作,以2开头的是更新操作 1 w 表示在总区间内查询一个长度为w的可用区间并且要最靠左,能找到的话返回这个区间的左端点并占用了这个区间,找不到返回0 2 a len , 表示从单位a开始,清除一段长度为len的区间(将其变为可用,不被占用),不需要输出. 思路: 这是第一次遇到线段树区间合并的题目,写下感悟,还是对线段的更新和查询工作,但是查询的对象的性质已经不像单点那样,查询的是某个线段的最大可用区间是多少,还要一并

线段树 区间合并

poj3667 Hotel 区间合并入门题,照着代码打的, 题意:1 a:询问是不是有连续长度为a的空房间,有的话住进最左边       2 a b:将[a,a+b-1]的房间清空思路:记录区间中最长的空房间,开三个数组,msum[rt]表示节点rt内连续的1的个数的最大值,lsum[rt]表示从节点rt左端点开始连续1的个数,rsum[rt]表示从节点rt右端点开始连续1的个数..线段树操作:update:区间替换 query:询问满足条件的最左端点 1 #include<iostream>