【题解】poj3667(2018-07-28校赛 线段树入门2 E) 线段树

本文介绍了如何使用线段树解决poj3667问题,该问题与求解最大连续子段和类似,涉及线段树在区间操作中的应用。内容包括题目描述、解题思路及线段树在处理入住和退房操作中的应用。

题目

题目链接
思路参考了大佬题解

#include<cstdio>
#include<algorithm>
using namespace std;
#define lc o<<1
#define rc o<<1|1
const int N=5e4+10;
int n,m;
int mx[N<<2],lmax[N<<2],rmax[N<<2],lazy[N<<2];
void push_up(int o,int l,int r)
{
    lmax[o]=lmax[lc];
    rmax[o]=rmax[rc];
    int mid=l+r>>1;
    if(lmax[o]==mid-l+1)lmax[o]+=lmax[rc];
    if(rmax[o]==r-mid)rmax[o]+=rmax[lc];
    mx[o]=max(mx[lc],max(mx[rc],rmax[lc]+lmax[rc]));
}
void build(int o,int l,int r)
{
    lazy[o]=-1;
    mx[o]=lmax[o]=rmax[o]=r-l+1;
    if(l==r)return;
    int mid=l+r>>1;
    build(lc,l,mid);build(rc,mid+1,r);
}
void push_down(int o,int l,int r)
{
    if(lazy[o]==-1)return;//-1无操作 
    lazy[lc]=lazy[rc]=lazy[o];
    int mid=l+r>>1;
    if(lazy[o])//占满 
    {
        lmax[lc]=rmax[lc]=mx[lc]=0;
        lmax[rc]=rmax[rc]=mx[rc]=0;
    }
    else//清空 
    {
        lmax[lc]=rmax[lc]=mx[lc]=mid-l+1;
        lmax[rc]=rmax[rc]=mx[rc]=r-mid;
    }
    lazy[o]=-1;
}
int query(int o,int l,int r,int len)//返回第一个位置 
{
    if(l==r)return l;
    push_down(o,l,r);
    int mid=l+r>>1;
    if(mx[lc]>=len)return query(lc,l,mid,len);//全在左 
    else if(rmax[lc]+lmax[rc]>=len)return mid-rmax[lc]+1;//横跨两边 
    else return query(rc,mid+1,r,len);//全在右 
}
void update(int o,int l,int r,int nl,int nr,int op)//op=1占满,op=0清空 
{
    if(l==nl&&r==nr)
    {
        lazy[o]=op;
        if(op)mx[o]=lmax[o]=rmax[o]=0;
        else mx[o]=lmax[o]=rmax[o]=nr-nl+1;
        return;
    }
    push_down(o,l,r);
    int mid=l+r>>1;
    if(nr<=mid)update(lc,l,mid,nl,nr,op);
    else if(nl>mid)update(rc,mid+1,r,nl,nr,op);
    else update(lc,l,mid,nl,mid,op),update(rc,mid+1,r,mid+1,nr,op);
    push_up(o,l,r);
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int op,x,y;
        scanf("%d%d",&op,&x);
        if(op&1)
        {
            if(mx[1]<x){puts("0");continue;}
            y=query(1,1,n,x);
            printf("%d\n",y);
            update(1,1,n,y,y+x-1,1);//1表示占用 
        }
        else
        {
            scanf("%d",&y);
            update(1,1,n,x,x+y-1,0);//0表示清空 
        }
    }
    return 0;
}

总结

这题有点像CH4301求最大连续子段和,同样是建立一个最长空房mx,紧靠左侧的最长空房lmax,紧靠右侧的最长空房rmax,不同的只是多了个入住和退房操作。感觉类似于求一个区间的题可以这样定义数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值