POJ 3667

维护左连续,右连续区间最大值,同时维护区间内最大的连续区间值。同时是使用标记法完成。很强大。

注意出现的状态-1,很巧妙,代表该结点不能再下传了,即不符合下传条件。

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

const int maxn = 55555;
int lsum[maxn<<2] , rsum[maxn<<2] , msum[maxn<<2];
int cover[maxn<<2]; 

void build(int rt,int l,int r){
	cover[rt]=-1;
	lsum[rt]=rsum[rt]=msum[rt]=r-l+1;
	if(l==r) return;
	int m=(l+r)>>1;
	build(rt<<1,l,m);
	build(rt<<1|1,m+1,r);
}

void PushDown(int rt,int m){
	if(cover[rt]!=-1){
		cover[rt<<1]=cover[rt<<1|1]=cover[rt];
		lsum[rt<<1]=rsum[rt<<1]=msum[rt<<1]=cover[rt]?0:(m-(m>>1));
		lsum[rt<<1|1]=rsum[rt<<1|1]=msum[rt<<1|1]=cover[rt]?0:(m>>1);
		cover[rt]=-1;
	}
}

void PushUp(int rt,int m){
	lsum[rt]=lsum[rt<<1];
	rsum[rt]=rsum[rt<<1|1];
	if(lsum[rt]==(m-(m>>1))) lsum[rt]+=lsum[rt<<1|1];
	if(rsum[rt]==(m>>1)) rsum[rt]+=rsum[rt<<1];
	msum[rt]=max(lsum[rt<<1|1]+rsum[rt<<1],max(msum[rt<<1],msum[rt<<1|1]));
	msum[rt]=max(msum[rt],lsum[rt]);
	msum[rt]=max(msum[rt],rsum[rt]);
}

int query(int rt,int l,int r,int w){
	if(l==r) return l;
	PushDown(rt,r-l+1);
	int m=(l+r)>>1;
	if(msum[rt<<1]>=w) return query(rt<<1,l,m,w);
	else if(rsum[rt<<1]+lsum[rt<<1|1]>=w) return m-rsum[rt<<1]+1;
	return query(rt<<1|1,m+1,r,w);
}

void update(int rt,int L,int R,int l,int r,int c){
	if(L<=l&&r<=R){
		cover[rt]=c;
		lsum[rt]=rsum[rt]=msum[rt]=c?0:r-l+1;
		return ;
	}
	PushDown(rt,r-l+1);
	int m=(l+r)>>1;
	if(L<=m) update(rt<<1,L,R,l,m,c);
	if(m<R) update(rt<<1|1,L,R,m+1,r,c);
	PushUp(rt,r-l+1);
}

int main(){
	int n,m,op,a,b;
	while(scanf("%d%d",&n,&m)!=EOF){
		build(1,1,n);
		for(int i=1;i<=m;i++){
			scanf("%d",&op);
			if(op==1){
				scanf("%d",&a);
				if(msum[1]>=a){
					int p=query(1,1,n,a);
					update(1,p,p+a-1,1,n,1);
					printf("%d\n",p);
				}
				else printf("0\n");
			}
			else{
				scanf("%d%d",&a,&b);
				update(1,a,a+b-1,1,n,0);
			}
		}
	}
	return 0;
}

  

时间: 2024-08-05 15:46:57

POJ 3667的相关文章

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 线段树的区间合并简单问题

题目大意:有一排标号1-N的房间.操作一:询问是不是有连续长度为a的空房间,有的话住进最左边(占用a个房间)操作二:将[a,a+b-1]的房间清空(腾出b个房间)思路:记录每个区间中“靠左”“靠右”“中间”的空房间线段树操作:update:区间替换query:询问满足条件的最左端点 题目链接: http://vjudge.net/problem/viewProblem.action?id=10354 题目操作: 因为这里找从最左边住起的房间,所以这里不能像常规地写query函数那样写了,终于发现

POJ 3667 Hotel(线段树)

POJ 3667 Hotel 题目链接 题意:有n个房间,现在有两个操作 1.找到连续长度a的空房间,入住,要尽量靠左边,如果有输出最左边的房间标号,如果没有输出0 2.清空[a, a + b - 1]的房间 思路:线段树的区间合并,记录下左边连续最长和右边连续最长空房间,和每一段的最大值,这样pushup的时候就是进行区间合并,注意查询的时候由于是要尽量左,所以先查左孩子,在查横跨左右的,在查右孩子 代码: #include <cstdio> #include <cstring>

POJ 3667 Hotel

Hotel Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 16782   Accepted: 7303 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 - 线段树

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

题目链接:http://poj.org/problem?id=3667 题意:宾馆有n个房间.有人来入住.共有2种操作 输入1和d,表示查询最左的连续d个空房间数的起始位置. 输入2,x和d,表示将从x开始长度为d的连续的房间清空. 思路:裸的区间合并.每个结点区间[l,r]存从左端点l开始向右最大连续空房间数lm,从右端点r开始向左最大连续空房间数rm和当前区间内最大连续空房间数. 代码: #include <iostream> #include <stdio.h> #inclu

poj 3667(线段树 区间合并) 开房吧

http://poj.org/problem?id=3667 宾馆有n个房间编号1到n都为空房,然后m个询问,当输入第一个为1的时候,代表要住进x个连续的房间,输入房间号最小的数,如果没有 输出0.当第一个数为2的时候,将从x号到y号的房间又变为空房,没有输出 与区间有关想想用线段树可不可以解决,就像是涂颜色一样把住与未住的房间号做个标记就行,问题是这里给的是区间的长度,并不是 具体的区间,处理起来比较麻烦 还要去找合适的区间,所以引入了len1表示某区间可用的最大长度,len2表示从区间左端开

POJ 3667 线段树区间合并

http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html 用线段树,首先要定义好线段树的节点信息,一般看到一个问题,很难很快能确定线段树要记录的信息做线段树不能为了做题而做,首先线段树是一种辅助结构,它是为问题而生的,因而必须具体问题具体分析回忆一下RMQ问题,其实解决RMQ有很多方法,根本不需要用到线段树,用线段树解决RMQ,其实是利用线段树的性质来辅助解决这个问题回忆一下求矩形面积并或周长并的问题,一般使用的是扫描