POJ 3667 Hotel

本文详细解析了线段树区间合并的经典问题,并提供了完整的C++代码实现。通过构建线段树并进行区间更新和查询操作,解决了一系列实际应用中的数据结构问题。

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

线段树区间合并经典题。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define rep(a,b,i) for(i=a;i<=b;i++)
#define maxn 50005
using namespace std;
struct pi{
    int l;
    int r;
    int max;
    int la;
}pp[4*maxn];
int mmax(int a,int b){
    if(a>b)
        return a;
    return b;
}
void pushdown(int tot,int le,int ri){
    if(pp[tot].la==0)
        return ;
    pp[2*tot+1].la=pp[2*tot+2].la=pp[tot].la;
    pp[tot].la=0;
    if(pp[2*tot+1].la==2) pp[2*tot+1].r=pp[2*tot+1].l=pp[2*tot+1].max=((le+ri)/2-le+1);
    if(pp[2*tot+2].la==2) pp[2*tot+2].r=pp[2*tot+2].l=pp[2*tot+2].max=(ri-(le+ri)/2);
    if(pp[2*tot+1].la==1) pp[2*tot+1].r=pp[2*tot+1].l=pp[2*tot+1].max=0;
    if(pp[2*tot+2].la==1) pp[2*tot+2].r=pp[2*tot+2].l=pp[2*tot+2].max=0;
}
void build(int tot,int le,int ri){
    pp[tot].l=ri-le+1;
    pp[tot].r=ri-le+1;
    pp[tot].max=ri-le+1;
    pp[tot].la=2;
    if(le==ri)
        return ;
    build(2*tot+1,le,(le+ri)/2);
    build(2*tot+2,(le+ri)/2+1,ri);
}
void pushup(int tot,int le,int ri){
    if(pp[2*tot+1].la==1)
        pp[tot].l=0;
    else
        pp[tot].l=pp[2*tot+1].l;
    if(pp[2*tot+2].la==1){
        pp[tot].r=0;
    }
    else{
        pp[tot].r=pp[2*tot+2].r;
    }
    if(!(pp[2*tot+1].la==1)&&pp[2*tot+1].l==(le+ri)/2-le+1){
        if(!(pp[2*tot+2].la==1))
        pp[tot].l+=pp[2*tot+2].l;
    }
    if(!(pp[2*tot+2].la==1)&&pp[2*tot+2].r==ri-(le+ri)/2){
        if(!(pp[2*tot+1].la==1))
        pp[tot].r+=pp[2*tot+1].r;
    }
    int p=0,q=0,f=0;
    if(pp[2*tot+1].la==1){
        p=0;
    }
    else if(pp[2*tot+1].la==2){
        p=(le+ri)/2-le+1;
        f+=p;
    }
    else{
        p=pp[2*tot+1].max;
        f+=pp[2*tot+1].r;
    }
    if(pp[2*tot+2].la==1)
        q=0;
    else if(pp[2*tot+2].la==2){
        q=ri-(le+ri)/2;
        f+=q;
    }
    else{
        q=pp[2*tot+2].max;
        f+=pp[2*tot+2].l;
    }
    pp[tot].max=mmax(mmax(p,q),f);
    if(pp[tot].max==ri-le+1)
        pp[tot].la=2;
    if(pp[tot].max==0)
        pp[tot].la=1;
    return ;
}
void update1(int tot,int l,int r,int le,int ri){
    if(l<=le&&r>=ri){
        pp[tot].la=1;
        pp[tot].r=pp[tot].l=pp[tot].max=0;
        return ;
    }
    int mid=(le+ri)/2;
    pushdown(tot,le,ri);
    if(l<=mid)
        update1(2*tot+1,l,r,le,mid);
    if(r>mid)
        update1(2*tot+2,l,r,mid+1,ri);
    pushup(tot,le,ri);
}
void update2(int tot,int l,int r,int le,int ri){
    if(l<=le&&r>=ri){
        pp[tot].la=2;
        pp[tot].r=pp[tot].l=pp[tot].max=(ri-le)+1;
        return ;
    }
    pushdown(tot,le,ri);
    int mid=(le+ri)/2;
    if(l<=mid)
        update2(2*tot+1,l,r,le,mid);
    if(r>mid)
        update2(2*tot+2,l,r,mid+1,ri);
    pushup(tot,le,ri);
}
int query(int tot,int le,int ri,int p){
    if(pp[tot].la==1)
        return 0;
    if(pp[tot].max<p)
        return 0;
    if(pp[tot].la==2)
        return le;
    int q;
    q=query(2*tot+1,le,(le+ri)/2,p);
    if(q)
        return q;
    int s=0,f=0;;
    if(pp[2*tot+1].la!=1){
        f=pp[2*tot+1].r;
        s+=pp[2*tot+1].r;
    }
    if(pp[2*tot+2].la!=1)
        s+=pp[2*tot+2].l;
    if(s>=p)
        return (le+ri)/2-f+1;
    return query(2*tot+2,(le+ri)/2+1,ri,p);
}
int main()
{
    int i,n,m,k,p,t;
    while(cin>>n>>m)
    {
        build(0,1,n);
        for(i=0;i<m;i++){
            scanf("%d",&p);
            if(p==1){
                scanf("%d",&t);
                k=query(0,1,n,t);
                printf("%d\n",k);
                if(k!=0){
                    update1(0,k,k+t-1,1,n);
                }
            }
            else{
                scanf("%d%d",&k,&p);
                update2(0,k,k+p-1,1,n);
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值