POJ 3667 Hotel

题目大意:

1 a:询问是不是有连续长度为a的空房间,有的话住进最左边

2 a b:将[a,a+b-1]的房间清空

思路:线段树的区间合并。

用cov记录区段的状态,-1代表没有被更新,0代表空闲,1代表是有人入住的。

用lmax代表从左端点开始最长的空闲区间,rmax代表从右开始最长的区间。tree代表自己这个区间内拥有的最大区间。

接下来就是两个重要的函数:pushdown  pushup了

void pushup(int num,int mid)
{
    lmax[num]=lmax[num<<1];
    rmax[num]=rmax[num<<1|1];
    if(lmax[num]==(mid-(mid>>1)))lmax[num]+=lmax[num<<1|1];
    if(rmax[num]==(mid>>1))rmax[num]+=rmax[num<<1];
    tree[num]=max(tree[num<<1],max(tree[num<<1|1],rmax[num<<1]+lmax[num<<1|1]));
}

首先在不考虑左右最大区间重叠的情况下,左边最大区间是左儿子的最大左区间,右边的最大区间是又儿子的最大右区间。

lmax[num]==(mid-(mid>>1))时,就代表左边全部是空闲的,就要考虑一个最大的区间被分成了两边了,就再加上右儿子的最大左区间。

同理。

最后更新最大区间的时候  就要三者做比较    最大的左  最大的右   左右之间的部分。

 

#include <iostream>

#include <cstdio>

#include <algorithm>

#define MAXN 50005

using namespace std;



int tree[MAXN<<2];

int lmax[MAXN<<2];

int rmax[MAXN<<2];

int cov[MAXN<<2];



void pushup(int num,int mid)

{

    lmax[num]=lmax[num<<1];

    rmax[num]=rmax[num<<1|1];

    if(lmax[num]==(mid-(mid>>1)))lmax[num]+=lmax[num<<1|1];

    if(rmax[num]==(mid>>1))rmax[num]+=rmax[num<<1];

    tree[num]=max(tree[num<<1],max(tree[num<<1|1],rmax[num<<1]+lmax[num<<1|1]));

}



void pushdown(int num,int mid)

{

    if(cov[num]!=-1)

    {

        cov[num<<1] = cov[num<<1|1] = cov[num];

        tree[num<<1] = lmax[num<<1] = rmax[num<<1] = cov[num] ? 0: (mid - (mid>>1));

        tree[num<<1|1] = lmax[num<<1|1] = rmax[num<<1|1] = cov[num] ? 0:(mid>>1);

        cov[num]=-1;

    }

}





void build(int num,int l,int r)

{

    lmax[num] = rmax[num] = tree[num] = r - l + 1;

    cov[num] = -1;

    if(r==l)return;

    int mid = (r+l)>>1;

    build(num<<1,l,mid);

    build(num<<1|1,mid+1,r);

}





int query(int num,int s,int e,int w)

{

    if(e==s)

    return s;

    pushdown(num,e-s+1);

    int mid = (s+e)>>1;



    if(tree[num<<1]>=w)return query(num<<1,s,mid,w);

    else if(rmax[num<<1] + lmax[num<<1|1] >=w)return mid + 1 - rmax[num<<1];



    return query(num<<1|1,mid+1,e,w);

}



void update(int num,int s,int e,int l,int r,int v)

{

    if(l<=s && e<=r)

    {

        tree[num] = lmax[num] = rmax[num] = v ? 0 : e-s+1;

        cov[num] = v;

        return ;

    }

    pushdown(num,e-s+1);

    int mid = (e+s)>>1;

    if(l<=mid)update(num<<1,s,mid,l,r,v);

    if(r>mid)update(num<<1|1,mid+1,e,l,r,v);

    pushup(num,e-s+1);

}





int main()

{

    int n,m;



        scanf("%d%d",&n,&m);

        build(1,1,n);

        for(int i=1;i<=m;i++)

        {

            int a,b,c;

            scanf("%d",&a);



            if(a==1)

            {

                scanf("%d",&b);

                if(tree[1]<b)puts("0");

                else {

                int p=query(1,1,n,b);

                printf("%d\n",p);

                update(1,1,n,p,p+b-1,1);

                }

            }

            else

            {

                scanf("%d%d",&b,&c);

                update(1,1,n,b,b+c-1,0);

            }

        }

        return 0;

}




 

 

你可能感兴趣的:(poj)