(3667)POJ

#include<iostream>
#include<cstdio>
#include<string.h>
#include<cstring>
#include<string>
#include<stack>
#include<set>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>

#define LOCAL
#define ll long long
#define lll unsigned long long
#define MAX 1000009
#define eps 1e-8
#define INF 0x7fffffff
#define mod 1000000007
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;
/*

题意:1操作,判断是否可以住下x个,如果可以,输出最左端的房间号
            2操作,清空x~x+y房间

想法:线段树,区间合并

ps:http://www.cnblogs.com/yewei/archive/2012/05/05/2484471.html

*/
const int maxn = 55555;
int cover[maxn<<2];//cover标志对应区间是否为空(1,0,-1三个标志状态)
int lsum[maxn<<2];//维护一个区间从最左端开始可用的且连续的最大长度
int rsum[maxn<<2];//维护一个区间从最右端开始可用的且连续的最大长度
int msum[maxn<<2];//维护1~n的最大长度
int n,m;

void build(int l,int r,int rt)//初始化左右区间的最大长度和全体的最大长度
{
    cover[rt] = -1;
    lsum[rt] = rsum[rt] = msum[rt] = r - l + 1;//可用长度
    if(l==r) return ;
    int m = (l+r)>>1;
    build(lson);
    build(rson);
}

void PushDown(int rt,int k)
{
    if(cover[rt]!=-1)
    {
        cover[rt<<1] = cover[rt<<1|1] = cover[rt];
        lsum[rt<<1] = rsum[rt<<1] = msum[rt<<1] = cover[rt] ?0:(k - (k>>1));
        lsum[rt<<1|1] = rsum[rt<<1|1] = msum[rt<<1|1] = cover[rt] ?0: (k>>1);
        cover[rt] = -1;
    }
}
void PushUp(int rt,int k)
{
    lsum[rt] = lsum[rt<<1];//左半区间部分能用: 当前区间llen = 左半区间llen
    rsum[rt] = rsum[rt<<1|1];//右半区间部分能用: 当前区间rlen = 右半区间rlen
    if(lsum[rt] == k - (k>>1))//如果左半区间全部可以用: 当前区间llen = 左半区间llen(tlen) + 右半区间llen
        lsum[rt]+=lsum[rt<<1|1];
    if(rsum[rt] == k>>1)//如果右半区间全部能用: 当前区间rlen = 右半区间rlen(tlen) + 左半区间rlen
        rsum[rt]+=rsum[rt<<1];
    msum[rt] = max(lsum[rt<<1|1]+rsum[rt<<1],max(msum[rt<<1],msum[rt<<1|1]));//选择左中右最大值
}
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;
        cover[rt] = c;
        return ;
    }
    PushDown(rt,r - l + 1);
    int m = (l+r)>>1;
    if(L<=m) update(L,R,c,lson);
    if(m<R) update(L,R,c,rson);
    PushUp(rt,r - l + 1);
}
int query(int w,int l,int r,int rt)
{
    if(l==r) return 1;
    PushDown(rt,r - l + 1);
    int m = (l+r)>>1;
    if(msum[rt<<1]>=w) return query(w,lson);
    else if((lsum[rt<<1|1]+rsum[rt<<1])>=w) return m - rsum[rt<<1] + 1;//返回最左边那个
    return query(w,rson);
}

int main()
{
    //freopen("date.in","r",stdin);
    while(~scanf("%d%d",&n,&m))
    {
        build(1,n,1);
        while(m--)
        {
            int op , a , b;
            scanf("%d",&op);
            if(op == 1)
            {
                scanf("%d",&a);
                if(msum[1]<a)//如果根节点的大小不够返回0
                    puts("0");
                else
                {
                    int p = query(a,1,n,1);
                    printf("%d\n",p);
                    update(p,p+a - 1,1, 1,n,1);//更新为1,表示已经住了,
                }
            }
            else
            {
                scanf("%d%d",&a,&b);
                update(a,a+b - 1,0,1,n,1);//清空为0
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值