POJ 3667 Hotel 线段树 区间合并

第一道这样的题目,转自这里点击打开链接

只是照抄了一下,然后体味了一下大神的思维,以及自己的不慎

#include<cstdio>
#include<iostream>
#include<cstring>
#define left l,m,x<<1
#define right m+1,r,x<<1|1
#define LMT 50005
using namespace std;
//一般都是左子树多一点
int msum[LMT<<2],rsum[LMT<<2],lsum[LMT<<2],cover[LMT<<2];
//msum指的是在某个区间“内”的最大空白
int max(int a,int b)
{
    return a>b?a:b;
}
void build(int l,int r,int x)
{
    msum[x]=lsum[x]=rsum[x]=r-l+1;
    if(l==r)return;
    int m=(l+r)>>1;
    build(left);build(right);
}
void cut(int x,int have)
{
    if(cover[x]!=-1)
    {
        cover[x<<1]=cover[x<<1|1]=cover[x];
        msum[x<<1]=lsum[x<<1]=rsum[x<<1]=cover[x]?0:have-(have>>1);
        msum[x<<1|1]=lsum[x<<1|1]=rsum[x<<1|1]=cover[x]?0:have>>1;
        cover[x]=-1;
    }
}
/***
这个函数是子树重新覆盖后,记录对父节点的影响的
***/
void refill(int x,int have)
{
    lsum[x]=lsum[x<<1];
    rsum[x]=rsum[x<<1|1];
    if(lsum[x]==have-(have>>1))lsum[x]+=lsum[x<<1|1];
    if(rsum[x]==have>>1)rsum[x]+=rsum[x<<1];//别搞错了..
    msum[x]=max(rsum[x<<1]+lsum[x<<1|1],max(msum[x<<1],msum[x<<1|1]));
}
void update(int L,int R,int c,int l,int r,int x)
{
    if(L<=l&&r<=R)
    {
        msum[x]=rsum[x]=lsum[x]=c?0:r-l+1;
        cover[x]=c;
        return;
    }
    cut(x,r-l+1);
    int m=(l+r)>>1;
    if(L<=m)update(L,R,c,left);
    if(R>m)update(L,R,c,right);
    refill(x,r-l+1);
}
int query(int need,int l,int r,int x)
{
    if(l==r)return l;
    cut(x,r-l+1);
    int m=(l+r)>>1;
    if(msum[x<<1]>=need)return query(need,left);
    if(rsum[x<<1]+lsum[x<<1|1]>=need)return m-rsum[x<<1]+1;
    return query(need,right);
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    build(1,n,1);
    memset(cover,-1,sizeof cover);
    while(m--)
    {
        int op,a,b,ans;
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d",&a);
            if(msum[1]<a)printf("0\n");
            else
            {
                ans=query(a,1,n,1);
                printf("%d\n",ans);
                update(ans,ans+a-1,1,1,n,1);
            }
        }
        else
        {
            scanf("%d%d",&a,&b);
            update(a,a+b-1,0,1,n,1);
        }
    }
    return 0;
}


你可能感兴趣的:(POJ 3667 Hotel 线段树 区间合并)