POJ 3667 Hotel (线段树区间合并)

本文详细解析了一道关于区间合并的线段树算法题目,介绍了如何通过维护四个关键值来实现区间合并,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

一个旅店,有n个房间,接下来会住进一些人,每个人要一段连续的房间,如果有多个,要编号最小的,同时也可能会出去一些人,每次都是出去一个区间的人

思路:

区间合并的模板题
区间合并其实很简单,以前我们对于父亲更新儿子,会用lazy来减少操作。用儿子更新父亲,也只是一些很简单的相加什么的,区间合并,是因为儿子对父亲产生的影响变得更加复杂,比如这个题目,左右儿子都需要维护的是区间,而在合并的时候,左右儿子接触的地方会产生问题
这个题目我们维护四个值,一个是从左起的连续没有人区间长度lsum,一个是从右起的连续没有人区间长度rsum,一个是区间最长的没人区间msum,当然,还有lazy。
在合并的时候,判断下左右儿子的lsum和rsum是否处于极端情况就可以轻松合并了(极端情况就是全部没人),这样区间合并就变成了正常的线段树了

错误及反思:

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int N = 50010;
int lsum[N<<2],rsum[N<<2],msum[N<<2],lazy[N<<2];
int n,k,p,ta,tb;
void pushup(int l,int r,int rt)
{
    int m=(l+r)/2;
    msum[rt]=max(max(msum[rt<<1],msum[rt<<1|1]),lsum[rt<<1|1]+rsum[rt<<1]);
    if(lsum[rt<<1]==m-l+1) lsum[rt]=lsum[rt<<1]+lsum[rt<<1|1];
    else lsum[rt]=lsum[rt<<1];
    if(lsum[rt<<1|1]==r-m) rsum[rt]=rsum[rt<<1|1]+rsum[rt<<1];
    else rsum[rt]=rsum[rt<<1|1];
}
void pushdown(int l,int r,int rt)
{
    if(lazy[rt]!=-1)
    {
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        int m=(l+r)/2;
        if(lazy[rt]){
            lsum[rt<<1]=rsum[rt<<1]=msum[rt<<1]=m-l+1;
            lsum[rt<<1|1]=rsum[rt<<1|1]=msum[rt<<1|1]=r-m;
        }
        else{
            lsum[rt<<1]=rsum[rt<<1]=msum[rt<<1]=0;
            lsum[rt<<1|1]=rsum[rt<<1|1]=msum[rt<<1|1]=0;
        }
        lazy[rt]=-1;
    }
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        lsum[rt]=rsum[rt]=msum[rt]=1;
        return ;
    }
    int m=(l+r)/2;
    build(lson);
    build(rson);
    pushup(l,r,rt);
}
void update(int L,int R,int v,int l,int r,int rt)
{
    if(L<=l&&R>=r)
    {
        lazy[rt]=v;
        if(v) lsum[rt]=rsum[rt]=msum[rt]=r-l+1;
        else lsum[rt]=rsum[rt]=msum[rt]=0;
        return ;
    }
    pushdown(l,r,rt);
    int m=(l+r)/2;
    if(L<=m) update(L,R,v,lson);
    if(R>m) update(L,R,v,rson);
    pushup(l,r,rt);
}
int query(int v,int l,int r,int rt)
{
    if(l==r) return l;
    pushdown(l,r,rt);
    int m=(l+r)/2;
    if(msum[rt<<1]>=v) return query(v,lson);
    else if(rsum[rt<<1]+lsum[rt<<1|1]>=v) return m-rsum[rt<<1]+1;
    return query(v,rson);
}
int main()
{
    memset(lazy,-1,sizeof(lazy));
    scanf("%d%d",&n,&k);
    build(1,n,1);
    while(k--)
    {
        scanf("%d",&p);
        if(p==1)
        {
            scanf("%d",&ta);
            if(msum[1]<ta) printf("0\n");
            else{
                int ans=query(ta,1,n,1);
                printf("%d\n",ans);
                update(ans,ans+ta-1,0,1,n,1);
            }
        }
        else
        {
            scanf("%d%d",&ta,&tb);
            update(ta,ta+tb-1,1,1,n,1);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值