Hotel POJ - 3667

点击打开链接

 

区间合并模板

 

 

tree[cur].left tree[cur].right 分别代表从左端点向右和从右端点向左的连续区间长度

而 tree[cur].all 则代表整个区间内最长连续区间的长度

 

利用区间合并 找到符合条件区间的左端点

 

先看当前区间的左孩子区间能否放下 再看左右孩子共有的区间能否放下 不能则在右孩子

 

 

 

 

 

 

 

 

 

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

struct node
{
    int l;
    int r;
    int laz;
    int left;
    int right;
    int all;
};

node tree[200010];
int n;

void pushup(int cur)
{
    tree[cur].left=tree[cur*2].left;
    tree[cur].right=tree[cur*2+1].right;
    if(tree[cur].left==tree[cur*2].r-tree[cur*2].l+1) tree[cur].left+=tree[cur*2+1].left;
    if(tree[cur].right==tree[cur*2+1].r-tree[cur*2+1].l+1) tree[cur].right+=tree[cur*2].right;
    tree[cur].all=max(tree[cur*2].right+tree[cur*2+1].left,max(tree[cur*2].all,tree[cur*2+1].all));
    return;
}

void pushdown(int cur)
{
    if(tree[cur].laz!=-1)
    {
        tree[cur*2].laz=tree[cur].laz;
        tree[cur*2].left=(tree[cur*2].r-tree[cur*2].l+1)*tree[cur].laz;
        tree[cur*2].right=(tree[cur*2].r-tree[cur*2].l+1)*tree[cur].laz;
        tree[cur*2].all=(tree[cur*2].r-tree[cur*2].l+1)*tree[cur].laz;
        tree[cur*2+1].laz=tree[cur].laz;
        tree[cur*2+1].left=(tree[cur*2+1].r-tree[cur*2+1].l+1)*tree[cur].laz;
        tree[cur*2+1].right=(tree[cur*2+1].r-tree[cur*2+1].l+1)*tree[cur].laz;
        tree[cur*2+1].all=(tree[cur*2+1].r-tree[cur*2+1].l+1)*tree[cur].laz;
        tree[cur].laz=-1;
    }
    return;
}

void build(int l,int r,int cur)
{
    int m;
    tree[cur].l=l;
    tree[cur].r=r;
    tree[cur].laz=-1;
    if(l==r)
    {
        tree[cur].left=1;
        tree[cur].right=1;
        tree[cur].all=1;
        return;
    }
    m=(l+r)/2;
    build(l,m,cur*2);
    build(m+1,r,cur*2+1);
    pushup(cur);
    return;
}

int query(int val,int cur)
{
    if(tree[cur].l==tree[cur].r)
    {
        return tree[cur].l;
    }
    pushdown(cur);
    if(tree[cur*2].all>=val) return query(val,cur*2);
    else if(tree[cur*2].right+tree[cur*2+1].left>=val) return tree[cur*2].r-tree[cur*2].right+1;
    else return query(val,cur*2+1);
}

void update(int pl,int pr,int val,int cur)
{
    if(pl<=tree[cur].l&&tree[cur].r<=pr)
    {
        tree[cur].laz=val;
        tree[cur].left=(tree[cur].r-tree[cur].l+1)*val;
        tree[cur].right=(tree[cur].r-tree[cur].l+1)*val;
        tree[cur].all=(tree[cur].r-tree[cur].l+1)*val;
        return;
    }
    pushdown(cur);
    if(pl<=tree[cur*2].r) update(pl,pr,val,cur*2);
    if(pr>=tree[cur*2+1].l) update(pl,pr,val,cur*2+1);
    pushup(cur);
    return;
}

int main()
{
    int q,i,op,p,l,res;
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        build(1,n,1);
        while(q--)
        {
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d",&p);
                if(tree[1].all<p)
                {
                    printf("0\n");
                }
                else
                {
                    res=query(p,1);
                    update(res,res+p-1,0,1);
                    printf("%d\n",res);
                }
            }
            else
            {
                scanf("%d%d",&l,&p);
                update(l,l+p-1,1,1);
            }
        }
    }
    return 0;
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值