POJ3667-Hotel-线段树区间合并(模板)

题目链接:http://poj.org/problem?id=3667

线段树真是牛逼啊,这么多的功能。。。

这是个线段树维护区间合并的问题;我们要维护一个区间的从左端点开始的最长区间,右端点的最长区间,以及该区间的最长区间,有了这些信息我们就可以轻易的合并子节点的信息,简单更新了;

好吧,我就不详细介绍了,就贴一个我学习的博客吧,链接:http://blog.csdn.net/piaoyi0208/article/details/8149804

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
#include<cmath>
#include<stack>
#include<set>
#include<vector>
#include<algorithm>
#define LL long long
#define inf 1<<30
#define s(a) scanf("%d",&a)
#define Clear(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=50015;
int n,a,m,b;
struct node
{
    int l,r;
    int cover;  //  保存是否住人的信息;用-1,0,1表示;
    int ls,rs,ms;   //  分别表示左端点起最大长度,右端点起最大长度,和整个区间最大长度;
}node[N<<2];
void Push_Up(int l,int r,int rt)    //  想父节点更新;
{
    node[rt].ls=node[rt<<1].ls;
    node[rt].rs=node[rt<<1|1].rs;
    int mid=(l+r)>>1;
    if(node[rt].ls==mid-l+1) node[rt].ls+=node[rt<<1|1].ls;
    if(node[rt].rs==r-mid) node[rt].rs+=node[rt<<1].rs;
    node[rt].ms=max(max(node[rt<<1].ms,node[rt<<1|1].ms),node[rt<<1].rs+node[rt<<1|1].ls);
}
void Push_Down(int rt)
{
    if(node[rt].cover!=-1){     //  不等于-1表示需要向下更新;
        node[rt<<1].cover=node[rt<<1|1].cover=node[rt].cover;
        if(node[rt].cover){     //  如果等于1,说明将区间标记为0,即表示住人;
            node[rt<<1].ls=node[rt<<1].rs=node[rt<<1].ms=0;
            node[rt<<1|1].ls=node[rt<<1|1].rs=node[rt<<1|1].ms=0;
        }else{
            node[rt<<1].ls=node[rt<<1].rs=node[rt<<1].ms=node[rt<<1].r-node[rt<<1].l+1;
            node[rt<<1|1].ls=node[rt<<1|1].rs=node[rt<<1|1].ms=node[rt<<1|1].r-node[rt<<1|1].l+1;
        }
        node[rt].cover=-1;      //  已经向下更新了,清零;
    }
}
void Build(int l,int r,int rt)
{
    node[rt].l=l;
    node[rt].r=r;
    node[rt].cover=-1;
    node[rt].ls=node[rt].rs=node[rt].ms=r-l+1;
    if(l!=r){
        int mid=(l+r)>>1;
        Build(l,mid,rt<<1);
        Build(mid+1,r,rt<<1|1);
    }
}
void Updata(int l,int r,int v,int rt)
{
    int ll=node[rt].l,rr=node[rt].r;
    if(ll==l&&rr==r){
        node[rt].cover=v;
        if(v){
            node[rt].ls=node[rt].rs=node[rt].ms=0;
        }else{
            node[rt].ls=node[rt].rs=node[rt].ms=r-l+1;
        }
        return ;
    }
    Push_Down(rt);
    int mid=(ll+rr)>>1;
    if(r<=mid) Updata(l,r,v,rt<<1);
    else if(l>mid) Updata(l,r,v,rt<<1|1);
    else{
        Updata(l,mid,v,rt<<1);
        Updata(mid+1,r,v,rt<<1|1);
    }
    Push_Up(node[rt].l,node[rt].r,rt);
}
int Query(int l,int r,int v,int rt)
{
    if(l==r) return l;
    int mid=(l+r)>>1;
    Push_Down(rt);
    if(node[rt<<1].ms>=v) return Query(l,mid,v,rt<<1);
    else if(node[rt<<1].rs+node[rt<<1|1].ls>=v) return mid-node[rt<<1].rs+1;
    else return Query(mid+1,r,v,rt<<1|1);
}
int main()
{
    //freopen("../../in.txt","r",stdin);
    //freopen("../../out.txt","w",stdout);
    while(~scanf("%d%d",&n,&m)){
        Build(1,n,1);
        for(int i=0;i<m;i++){
            s(a);
            if(a==1){
                s(a);
                if(node[1].ms<a){
                    printf("0\n");
                    continue;
                }else{
                    b=Query(1,n,a,1);
                    printf("%d\n",b);
                    Updata(b,b+a-1,1,1);
                }
            }else{
                s(a); s(b);
                Updata(a,a+b-1,0,1);
            }
        }
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值