题目链接; poj 3667 Hotel
题意:有n个房间,m组询问,询问中第一个数字表示方式,1表示住人,后面的那个数表示住店的人数,2表示清空,后面跟着两个数字票p,q,表示从第p个房间开始数,q个房间清空,我们尽可能的要使人住在左边的房间且房间数必须连续,问你住店时从那个房间开始住;
#include<iostream>
#include<cstdio>
#define maxn 55555
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
int col[maxn<<2];//延迟标记,值为1时表示住人,0表示走人,-1表示此区间没有访问过,不用向下更新
int lsum[maxn<<2],rsum[maxn<<2],msum[maxn<<2];//lsum表示区间从最左边开始到右边的连续空位,rsum为区间从最右边开始到左边的连续空位,msum表示此区间最大的连续空间
void pushdown(int rt,int m)
{
if(col[rt]!=-1) //此区间之前被更新过,所以要向下更新
{
col[rt<<1]=col[rt<<1|1]=col[rt];//把此区间的的信息传递给它的子区间
lsum[rt<<1]=rsum[rt<<1]=msum[rt<<1]=col[rt]?0:(m-(m>>1));//左儿子,两种情况,一种col为1表示住人,空位变为0,否则就是走人,空位等于区间长度
lsum[rt<<1|1]=rsum[rt<<1|1]=msum[rt<<1|1]=col[rt]?0:(m>>1);//情况与左儿子相同
col[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(max(msum[rt<<1],msum[rt<<1|1]),rsum[rt<<1]+lsum[rt<<1|1]);//然后更新父区间整个连续空间的最大值,可能左儿子空间的最大,也可能是右儿子,也可能是左右儿子连通,他们的空间和最大
}
void build(int l,int r,int rt)
{
lsum[rt]=rsum[rt]=msum[rt]=r-l+1;//初始空间大小为区间长度
col[rt]=-1;//表示没有被标记过
if(l==r) return ;
int m=(l+r)>>1;
build(lson);
build(rson);
}
int query(int p,int l,int r,int rt)
{
if(l==r) return l;
pushdown(rt,r-l+1); //向下更新子节点
int m=(l+r)>>1;
if(p<=msum[rt<<1]) return query(p,lson); //如果所需空间数比左儿子的空间数小,则住在左区间
else if(rsum[rt<<1]+lsum[rt<<1|1]>=p) return m-rsum[rt<<1]+1;//若是比左儿子的右区间与右儿子左区间的和小,则直接返回左儿子右区间的最左端
return query(p,rson);//否则在右儿子里找
}
void update(int L,int R,int c,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
msum[rt]=lsum[rt]=rsum[rt]=c?0:r-l+1; //c为1表示住人,0,表示走人,住人则和变为0,走人则赋为区间长度
col[rt]=c;//改变区间的更新标志
return ;
}
pushdown(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m) update(L,R,c,lson);//往左半部分找
if(R>m) update(L,R,c,rson);//往右半部分找
pushup(rt,r-l+1);
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
build(1,n,1);
int op,a,b;
while(m--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d",&a);
if(msum[1]<a) printf("0\n"); //若开始总区间的最大空位小于所需空位,直接输出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;
}