poj 3667 Hotel

题意:在一个酒店里有一排房间从1到N标号,游客们要来住店,对于这些房间有两种操作,一种是查询有没有连续的n间房间,有的话就返回最小的房间号并标记入住,没有就返回0,另一种操作就是取消连续的房间a到b的入住。

线段树的基本题型,利用区间的合并就可解决。对于线段树中的每个节点需要记录区间范围[L,R],区间从左起连续的房间数lsum,区间从右边起连续的房间数rsum,区间最大的连续房间数sum,还有就是懒惰标记d(其中1表示入住,0表示取消入住,-1表示没有更新消息)。

代码:

#include <iostream>
#include <cstdio>
using namespace std;
#define maxn 55555
struct node
{
      int l, r, lsum, rsum, sum, d;
}v[maxn*4];
void build (int l, int r, int n)
{
      v[n].l = l;
      v[n].r = r;
      v[n].lsum = v[n].rsum = v[n].sum = r-l+1;
      v[n].d = -1;
      if (l==r)
            return ;
      int mid = (v[n].l + v[n].r) >> 1;
      build(l, mid, n<<1);
      build(mid+1, r, n<<1|1);
}
void pushdown(int n)
{
      if (v[n].d!=-1)
      {
            int t = v[n].r-v[n].l+1;
            v[n<<1].lsum = v[n<<1].rsum = v[n<<1].sum = v[n].d?0:t-(t>>1);
            v[n<<1|1].lsum = v[n<<1|1].rsum = v[n<<1|1].sum = v[n].d?0:(t>>1);
            v[n<<1].d = v[n<<1|1].d = v[n].d;
            v[n].d = -1;
      }
}
void pushup(int n)
{
      v[n].lsum = v[n<<1].lsum;
      v[n].rsum = v[n<<1|1].rsum;
      int t = v[n].r-v[n].l+1;
      if (v[n].lsum == t-(t>>1))
            v[n].lsum += v[n<<1|1].lsum;
      if (v[n].rsum == t>>1)
            v[n].rsum += v[n<<1].rsum;
      v[n].sum = max( v[n<<1].sum, max( v[n<<1|1].sum, v[n<<1].rsum+v[n<<1|1].lsum ) );
}
void update(int l, int r, int d, int n)
{
      if (l<=v[n].l && v[n].r<=r)
      {
            v[n].lsum = v[n].rsum = v[n].sum = d?0:r-l+1;
            v[n].d = d;
            return ;
      }
      pushdown(n);
      int mid = (v[n].l+v[n].r)>>1;
      if (r<=mid)
            update(l, r, d, n<<1);
      else if (l>mid)
            update(l, r, d, n<<1|1);
      else
      {
            update(l, mid, d, n<<1);
            update(mid+1, r, d, n<<1|1);
      }
      pushup(n);
}
int query(int w, int n)
{
      pushdown(n);
      int mid = (v[n].l+v[n].r)>>1;
      if (v[n<<1].sum>=w)
            return query(w, n<<1);
      else if (v[n<<1].rsum+v[n<<1|1].lsum>=w)
            return mid-v[n<<1].rsum+1;
      else
            return query(w, n<<1|1);
}
int main()
{
      int n, m, op, a, b;
      while (~scanf("%d%d", &n, &m))
      {
            build(1, n, 1);
            while (m--)
            {
                  scanf("%d", &op);
                  if (op==1)
                  {
                        scanf("%d", &a);
                        if (v[1].sum<a)
                              printf("0\n");
                        else
                        {
                              int t = query(a, 1);
                              printf("%d\n", t);
                              update(t, a+t-1, 1, 1);
                        }
                  }
                  else
                  {
                        scanf("%d%d", &a, &b);
                        update(a, a+b-1, 0, 1);
                  }
            }
      }
      return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值