poj 3667 线段树 区间合并

感想:

   没有什么说的了。。。。。越做线段树越感觉自己水。。。。。。。。这个我感觉自己就真坑了大家了。。。。。。。难的不会,简单的也水不过了。。。。。哎,最近这是什么情况啊!!!


/*
题目:http://poj.org/problem?id=3667
题意:旅馆有编号为1~n的房间,现在可能有m波人过了租房,
每波人可能要定连续的d间房,如果有的话,编号尽量小,没有的话就说0,
也可能有d个人要退房,他们的房是连续的x~x+d-1这几间。。。
分析:这题属于线段树区间合并,还是比较简单的。。。
首先,当然要记录一个区间最长的连续值了,这个方便取值,
然后要考虑一个区间如何从它的两子区间转移过来,这个最长的值肯定可以使连个值区间最长值的大者,
当然,两子区间合并,可能得到更长的,而这个更长的肯定在中间,
我们需要记录左子区间从右端开始到左端的最长连续值,记录右子区间从左端到右端的最长连续值,
新的值就是这两个值相加了,当然,由于不确定哪个区间是左区间,所以每个区间都要记录这三个值
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=50002;
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
int col[maxn<<2],lmax[maxn<<2],rmax[maxn<<2],mmax[maxn<<2],q,n,m;
void pushup(int rt,int l,int r)
{
    int mid=(l+r)>>1;
    mmax[rt]=max(mmax[rt<<1],mmax[rt<<1|1]);
    lmax[rt]=lmax[rt<<1];
    rmax[rt]=rmax[rt<<1|1];
    if(lmax[rt<<1]==mid-l+1) lmax[rt]+=lmax[rt<<1|1];
    if(rmax[rt<<1|1]==r-mid) rmax[rt]+=rmax[rt<<1];
    mmax[rt]=max(mmax[rt],lmax[rt<<1|1]+rmax[rt<<1]);
}
void pushdown(int rt,int l,int r)
{
    if(col[rt]!=-1)
    {
           int mid=(l+r)>>1;
            col[rt<<1]=col[rt<<1|1]=col[rt];
            if(col[rt]==1)
            {
                lmax[rt<<1]=rmax[rt<<1]=mmax[rt<<1]=rmax[rt<<1|1]=lmax[rt<<1|1]=mmax[rt<<1|1]=0;
            }
            else
            {
                 lmax[rt<<1]=rmax[rt<<1]=mmax[rt<<1]=mid-l+1;
                 lmax[rt<<1|1]=rmax[rt<<1|1]=mmax[rt<<1|1]=r-mid;
            }
            col[rt]=-1;
    }
}
void build(int rt,int l,int r)
{
    lmax[rt]=rmax[rt]=mmax[rt]=r-l+1;
    col[rt]=-1;///未被覆盖
    if(l==r)
    {
        return;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    //pushup(rt,l,r);
}
void updata(int rt,int l,int r,int L,int R,int val)
{
    if(L<=l&&r<=R)
    {
        col[rt]=val;
        lmax[rt]=rmax[rt]=mmax[rt]=(val?0:r-l+1);
        return;
    }
    pushdown(rt,l,r);
    int mid=(l+r)>>1;
    if(mid>=L) updata(lson,L,R,val);
    if(mid<R)  updata(rson,L,R,val);
    pushup(rt,l,r);
}
int query(int rt,int l,int r,int sum)
{
    if(mmax[rt]<sum)return 0;
    if(lmax[rt]>=sum) return l;
    pushdown(rt,l,r);
    int mid=(l+r)>>1;
    if(mmax[rt<<1]>=sum)return query(lson,sum);
    if(rmax[rt<<1]+lmax[rt<<1|1]>=sum) return mid-rmax[rt<<1]+1;
    return query(rson,sum);
}
int main()
{
    int a,b,sum;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        build(1,1,n);
        for(int i=1; i<=m; i++)
        {
            scanf("%d",&q);
            if(q==1)
            {
                scanf("%d",&sum);
                int ret=query(1,1,n,sum);
                printf("%d\n",ret);
                if(ret)
                updata(1,1,n,ret,ret+sum-1,1);///已经利用
            }
            else
            {
                scanf("%d%d",&a,&b);
                b=a+b-1;
                updata(1,1,n,a,b,0);///重新获得空间
            }
        }
    }
    return  0;
}


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