POJ 3667 hotel(shǎ崽大神的模板|区间合并)

继续线段树,这题其实是之前一次练习赛的题目,当时最后两小时苦憋这题。无奈一直TLE,只记得后来婷队讲解时还是一知半解,过了久了就忘记这题了。现在重新翻出来看看,是一道区间合并的题目。

英文一大堆,其实题意很简单:

输入 1 a:询问是不是有连续长度为a的空房间,有的话住进最左边
输入 2 a b:将[a,a+b-1]的房间清空
思路:记录区间中最长的空房间

依然套用了大神的模板代码,真是好用啊。

因为是统计存在的最长连续房间,左右将值分成了三段,计算的时候分三个,即纯左孩子剩余间输中计算和纯右孩子剩余间输中计算,还有一左一右。就三种,有点lazy-tag的感觉,要记得update的时候碰到满足条件也要更新孩子节点。

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int maxn=55555;
int lsum[maxn<<2],rsum[maxn<<2],msum[maxn<<2];   //左右,总的剩余间输
int cover[maxn<<2];         //取值有  -1(初始),0 ,其他值
int max(int a,int b)   //最大值函数
{
	return a>b?a:b;
}
void pushdown(int rt,int m)         //更新儿子节点
{
	if(cover[rt]!=-1)
	{
		cover[rt<<1]=cover[rt<<1|1]=cover[rt];
		msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=cover[rt]?0:m-(m>>1);
		msum[rt<<1|1]=lsum[rt<<1|1]=rsum[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]));        //根节点值  由下三段中最大值组成。纯左,纯右,一左一右
}
void build(int l,int r,int rt)     //建立
{
	msum[rt]=lsum[rt]=rsum[rt]=r-l+1;
	cover[rt]=-1;
	if(l==r) 
		return ;
	int mid=(l+r)>>1;
	build(lson);
	build(rson);
}
void update(int L,int R,int c,int l,int r,int rt)  //重要的是c的取值 0  还是非0
{
	if(L<=l&&r<=R)
	{
		msum[rt]=lsum[rt]=rsum[rt]=c?0:r-l+1;
		cover[rt]=c;
		return ;
	}
	pushdown(rt,r-l+1);
	int mid=(l+r)>>1;
	if(L<=mid)
		update(L,R,c,lson);
	if(mid<R)
		update(L,R,c,rson);
	pushup(rt,r-l+1);
}
int query(int w,int l,int r,int rt)
{
	if(l==r) 
		return l;
	pushdown(rt,r-l+1);  //lazy-tag
	int  mid=(l+r)>>1;
	if(msum[rt<<1]>=w)   //纯左孩子
		return query(w,lson);
	else 
		if(rsum[rt<<1]+lsum[rt<<1|1]>=w)   //一左一右
			return mid-rsum[rt<<1]+1;
		return query(w,rson);  //剩下纯右孩子
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	build(1,n,1);
	while(m--)
	{
		int op,a,b;
		scanf("%d",&op);
		if(op==1)
		{
			scanf("%d",&a);
			if(msum[1]<a)
				puts("0");
			else
			{
				int p=query(a,1,n,1);
				printf("%d\n",p);
				update(p,p+a-1,1,1,n,1);
			}
		}
		else
		{
			scanf("%d%d",&a,&b);
			update(a,a+b-1,0,1,n,1);
		}
	}
	return 0;
}

 

posted @ 2012-02-07 11:37  Lxsec  阅读(1371)  评论(0编辑  收藏  举报