POJ 3667 Hotel 线段树lazy标记 (模板~~)

传送门


题目大意:
某个闻名中外的旅店有n个房间(由于很著名,所以n<=5W),现在有m个旅客提出了要求,1 x代表这位旅客要预定x个连续的房间,并且编号越靠前越好,2 x y代表这位旅客要退x~x+y-1这一段连续的房间…
对于每次预定操作,输出第一个房间的编号,如果无法满足,输出0


分析:
(队长曾经说过…)我们先把题意简单化:
有一段1~n的区间,初始值为1,现在有m次操作,分为两种:
1、找到最靠前的长度为x的一段连续的1区间,并且把这段区间变为0…
2、把x~y这段0区间变为1…
简单来说,这道题就是一个区间修改,区间查询的题目,肯定需要数据结构,应该使用什么捏?
线段树…
记得某位神犇在博客里写道:做线段树不能为了做题而做,首先线段树是一种辅助结构,它是为问题而生的,因而必须具体问题具体分析…..
好有哲理的一段话说….>_<
写线段树,最重要的是要确定好线段树需要记录那些节点信息…
好了,不扯了,我们还是回归此题吧>_<…
这道题的修改操作就是最简单的修改操作,那么查询操作怎么办捏??
既然我们要查询的和区间长度有关系,那么我们的节点信息肯定也是区间长度…
话说我们一定至少需要3个信息:
1、midlen,就是区间内连续最长的一段1的长度
2、llen最长前缀1区间
3、rlen最长后缀1区间
话说2&3是干什么的(打酱油的>_<)
因为我们如果要维护midlen,那么llen&rlen是必不可少滴~~
接下来还有一个麻烦事—要求查询区间最靠前
(⊙o⊙)…
分类讨论吧…
1、如果左儿子的midlen>=x那么就返回query(左儿子)
2、如果左儿子的后缀+右儿子的前缀>=x,直接返回左儿子的后缀开始的下标
3、若果右儿子的midlen>=x那么就返回query(右儿子)
4、那就只能返回0了(忧桑~~>_<)


话说,线段树每次都虐我,而且每次写线段树基本都需要好几个小时,<( ̄3 ̄)>… 忧桑啊… ̄へ ̄


代码如下:
(模板copyMG)

#include
#include
#include
#include
using namespace std;
const int maxn=50000+5;
int n,m;
struct lala{
    int l,r,llen,rlen,midlen,lazy;//lazy=1全满,lazy=0全空,lazy=-1...自己体会吧
    void changelen(){
        midlen=llen=rlen=lazy*(r-l+1);
    } 
}tree[maxn*4];
inline void build(int tr,int l,int r){
    tree[tr].l=l,tree[tr].r=r,tree[tr].lazy=1;
    tree[tr].changelen();
    if(l==r)
        return;
    int mid=(tree[tr].r+tree[tr].l)>>1;
    build(tr<<1,l,mid),build(tr<<1|1,mid+1,r);
}
inline void change(int tr,int l,int r,int val){
    if(tree[tr].l==l&&tree[tr].r==r){
        tree[tr].lazy=val,tree[tr].changelen();
        return;
    }
    int mid=(tree[tr].l+tree[tr].r)>>1;
    if(tree[tr].lazy!=-1){
        tree[tr<<1].lazy=tree[tr<<1|1].lazy=tree[tr].lazy;
        tree[tr].lazy=-1;
        tree[tr<<1].changelen(),tree[tr<<1|1].changelen();
    }
    if(l>mid)
        change(tr<<1|1,l,r,val);
    else if(r<=mid)
        change(tr<<1,l,r,val);
    else
        change(tr<<1,l,mid,val),change(tr<<1|1,mid+1,r,val);
    int tmp=max(tree[tr<<1].midlen,tree[tr<<1|1].midlen);
    tree[tr].midlen=max(tmp,tree[tr<<1].rlen+tree[tr<<1|1].llen);
    tree[tr].llen=tree[tr<<1].llen,tree[tr].rlen=tree[tr<<1|1].rlen;
    if(tree[tr<<1].midlen==tree[tr<<1].r-tree[tr<<1].l+1)
        tree[tr].llen+=tree[tr<<1|1].llen;
    if(tree[tr<<1|1].midlen==tree[tr<<1|1].r-tree[tr<<1|1].l+1)
        tree[tr].rlen+=tree[tr<<1].rlen;
}
inline int query(int tr,int len){
    if(tree[tr].l==tree[tr].r&&len==1)
        return tree[tr].l;
    if(tree[tr].lazy!=-1){
        tree[tr<<1].lazy=tree[tr<<1|1].lazy=tree[tr].lazy;
        tree[tr].lazy=-1;
        tree[tr<<1].changelen(),tree[tr<<1|1].changelen();
    }
    if(tree[tr<<1].midlen>=len)
        return query(tr<<1,len);
    if(tree[tr<<1].rlen+tree[tr<<1|1].llen>=len)
        return tree[tr<<1].r-tree[tr<<1].rlen+1;
    if(tree[tr<<1|1].midlen>=len)
        return query(tr<<1|1,len);
    return 0;
} 
signed main(void){
    scanf("%d%d",&n,&m),build(1,1,n);
    while(m--){
        int x,y,z;
        scanf("%d",&z);
        if(z==1){
            scanf("%d",&x),cout<<(y=query(1,x))<if(y!=0)
                change(1,y,y+x-1,0);
        }
        else
            scanf("%d%d",&x,&y),change(1,x,x+y-1,1);
    }
    return 0;
}

by >_< neighthorn

你可能感兴趣的:(poj题解,模板,这里是数据结构的锦瑟流年)