题目大意:
很多旅游团去住宾馆,先到前台登记,要求是要住连在一起的房间。退得时候也是一起退,现在把房间的数量告诉你(1~n)要求你进行如下操作(m次).
1、每次有旅游团来的时候查询是否有满足条件(di个连续的房间)的空余的房间,如果有,安排入住,并且返回第一间房的房号(1~n).如果没有返回0
2、每次有有旅游团退房的时候清除该旅游团(xi~xi+di-1)所住的房间。
解题思路:
虽然知道是线段树的题目,但是平时敲得太少的无法下手,所以看了下大神的代码,模仿着写了一遍。
基本思路是,每个线段树的节点都标记区间左边界往右的连续房间数和右边界往左的连续房间数,以及该区间的最大的连续房间数,查找的时候能往左找就往左找,因为房间的起始值应该尽可能的小的。然后更新的时候没必要把所有节点都更新了,这个我前面已经简单的介绍过lazy思想的,不理解的自己百度一下。
贴个代码,注释写的很全面了,自己看吧。
#include<stdio.h>
#define N 50005
#define lson root<<1,l,mid
#define rson root<<1|1,mid+1,r
int mmax(int a,int b)
{
return a>b?a:b;
}
struct node
{
int lsum,rsum,sum;
int lazy;
};
node tree[N<<1];
//创建线段树,lsum节点往右的连续,rsum表示节点右端往左的连续,sum表示二者中的最大值,lazy用于lazy标记
void cr(int root,int l,int r)
{
tree[root].lazy=-1;
tree[root].lsum=tree[root].rsum=tree[root].sum=r-l+1;
if(l==r)
return ;
int mid=(l+r)>>1;
cr(lson);
cr(rson);
}
void up(int root,int sum)
{
tree[root].lsum=tree[root<<1].lsum; //左连续==左子树的左连续
tree[root].rsum=tree[root<<1|1].rsum; //右连续==右子树的右连续
if(tree[root<<1].lsum==sum-(sum>>1)) //左子树的连续满了,则左连续可以拓展到右子树的右连续
tree[root].lsum+=tree[root>>1|1].lsum;
if(tree[root<<1|1].rsum==(sum>>1)) //右子树连续满了,
tree[root].rsum+=tree[root>>1].rsum;
tree[root].sum=mmax(tree[root<<1|1].lsum+tree[root<<1].rsum,mmax(tree[root<<1].sum,tree[1<<1|1].sum));//左右,或左或右
}
void down(int root,int sum)
{
if(tree[root].lazy!=-1)//-1表示已更新,自然不在更新
{
tree[root<<1].lazy=tree[root<<1|1].lazy=tree[root].lazy;//根节点没跟新子节点就没更新,根节点要被清空,则子节点也是被清空。
tree[root<<1].sum=tree[root<<1].lsum=tree[root<<1].rsum=tree[root<<1].lazy?0:sum-(sum>>1);
tree[root<<1|1].sum=tree[root<<1|1].lsum=tree[root<<1|1].rsum=tree[root<<1|1].lazy?0:sum>>1;
tree[root].lazy=-1;//标记根节点已经被更新
}
}
void update(int st,int ed,int lazy,int root,int l,int r )
{
if(st<=l&&r<=ed)//把范围内的更新了
{
tree[root].lsum=tree[root].rsum=tree[root].sum=lazy?0:r-l+1;
tree[root].lazy=lazy;
return ;
}
down(root,r-l+1);//顺带把下面的更新了
int mid=(l+r)>>1;
if(st<=mid)
{
update(st,ed,lazy,lson);
}
if(mid<ed)
{
update(st,ed,lazy,rson);
}
up(root,r-l+1);//把根节点更新了
}
int query(int w,int root,int l,int r)
{
if(l==r)
return l;
down(root,r-l+1);
int mid=(l+r)>>1;
if(tree[root<<1].sum>=w)
return query(w,lson);
else
if((tree[root<<1].rsum+tree[root<<1|1].lsum)>=w)
return mid-tree[root<<1].rsum+1;
return query(w,rson);
}
int main()
{
int n,m,op,di,xi;
scanf("%d%d",&n,&m);
cr(1,1,n);
while(m--){
scanf("%d",&op);
if(op==1){
scanf("%d",&di);
if(tree[1].sum<di)
puts("0");
else{
int st=query(di,1,1,n);
printf("%d\n",st);
update(st,st+di-1,1,1,1,n);
}
}
else{
scanf("%d%d",&xi,&di);
update(xi,xi+di-1,0,1,1,n);
}
}
}
这个代码耗时900多MS,所以得优化,本篇博客有待更新。。。。