点我看题
题意:有L个连续的房间,日常会有一些人登记入住,也会有一些人退房,一次登记入住和一次退房都是连续的,问每次登记入住时,是否有连续的房间提供给入住者们,有的话,求入住的第一个房间序号.
分析:裸的线段树区间合并加查询,入住的时候,查询是否有满足条件的房间(st[1].sum>=所需要的房间数就是满足条件了),然后更新线段树,退房的话就更简单了,直接更新结点的长度就好.
参考代码:
/*区间合并*/
#include
#include
#include
#include
#include
using namespace std;
#define lson rt<<1
#define rson rt<<1|1
const int maxn = 5e4+10;
int n,q;
struct SegTree{
int l,r;
int sum;//当前结点保存的可入住人数的值
int lsum,rsum;//当前结点
int tag;//tag=1代表入住,-1代表退房,0代表不进行操作
};
SegTree st[maxn<<2];
//向上更新
void PushUp( int rt)
{
st[rt].lsum = st[lson].lsum;
st[rt].rsum = st[rson].rsum;
int mid = (st[rt].l+st[rt].r)>>1;
if( st[rt].lsum == mid-st[rt].l+1)
st[rt].lsum += st[rson].lsum;
if( st[rt].rsum == st[rt].r-mid)
st[rt].rsum += st[lson].rsum;
st[rt].sum = max(max(st[lson].sum,st[rson].sum),st[lson].rsum+st[rson].lsum);
}
//建树
void Build( int l, int r, int rt)
{
st[rt].l = l;
st[rt].r = r;
st[rt].sum = r-l+1;
st[rt].lsum = r-l+1;
st[rt].rsum = r-l+1;
st[rt].tag = 0;
if( l == r)
return;
int mid = (l+r)>>1;
Build(l,mid,lson);
Build(mid+1,r,rson);
// PushUp(rt);//这里不需要往上更新
}
//向下更新
void PushDown( int rt)
{
if( st[rt].tag != 0)
{
st[lson].tag = st[rson].tag = st[rt].tag;
if( st[rt].tag == 1)
{
st[lson].sum = st[lson].lsum = st[lson].rsum = 0;
st[rson].sum = st[rson].lsum = st[rson].rsum = 0;
}
else if( st[rt].tag == -1)
{
st[lson].sum = st[lson].lsum = st[lson].rsum = st[lson].r-st[lson].l+1;
st[rson].sum = st[rson].lsum = st[rson].rsum = st[rson].r-st[rson].l+1;
}
st[rt].tag = 0;
}
}
//区间查询
//查询有没有区间长度至少为len的区间
//个人认为这里的l和r都可以通过rt得到,但是为了书写方便,还是给加上去了
int Query( int l, int r, int rt, int len)
{
if( l == r)
return l;
PushDown(rt);//继续向下更新查找
int mid = (l+r)>>1;
if( st[lson].sum >= len)
return Query(l,mid,lson,len);
else if( st[lson].rsum+st[rson].lsum >= len)
return mid-st[lson].rsum+1;
else
return Query(mid+1,r,rson,len);
}
//区间合并
void Update( int L, int R, int rt, int tag)
{
if( st[rt].l == L && st[rt].r == R)
{
st[rt].tag = tag;
if( tag == 1)
st[rt].sum = st[rt].lsum = st[rt].rsum = 0;
else if( tag == -1)
st[rt].sum = st[rt].lsum = st[rt].rsum = st[rt].r-st[rt].l+1;
return;
}
PushDown(rt);//向下更新
int mid = (st[rt].l+st[rt].r)>>1;
if( R <= mid)
Update(L,R,lson,tag);
else if( L > mid)
Update(L,R,rson,tag);
else
{
Update(L,mid,lson,tag);
Update(mid+1,R,rson,tag);
}
PushUp(rt);//向上更新
}
int main()
{
while( ~scanf("%d%d",&n,&q))
{
Build(1,n,1);
while( q--)
{
int op;
int x,y;
scanf("%d",&op);
if( op == 1)
{
scanf("%d",&x);
if( x <= st[1].sum)
{
int pos = Query(1,n,1,x);
printf("%d\n",pos);
//pos和pos+x-1分别表示更新的起始和结束的位置
//第一个1为根结点,第二个1为tag标记
Update(pos,pos+x-1,1,1);
}
else
puts("0");
}
else if( op == 2)
{
scanf("%d%d",&x,&y);
//参数意义同上
Update(x,x+y-1,1,-1);
}
}
}
return 0;
}