POJ 3667 Hotel (线段树区间合并)

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

题目大意:一共有n个房间,初始时都是空的,现在有m个操作,操作有以下两种:

1.1 d :询问是否有连续d个空的房间,若有则输出连续房间的起始编号,若无则输出0

2.2 xi d:将第xi个房间至第xi+d-1个房间清空

 

解题思路:线段树维护区间最大连续长度,tree[cur].lm代表以区间左端点为起点的连续段的长度 tree[cur].rm代表以区间右端点为终点的连续段的长度,tree[2*cur].rm+tree[2*cur+1].lm代表包含该区间中点的连续段的长度 这是个隐含值(中间连续段),则区间内最长连续段值不止要从左右子节点的最长连续段中择最大 还要考虑该区间的中间连续段即tree[cur].len=max(tree[2*cur].rm+tree[2*cur+1].lm,max(tree[2*cur].len,tree[2*cur+1].len));

 

 

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=50007;
int n,m;
struct node{
    int lm,rm,len,cov;
}tree[maxn<<2];

void pushup(int len,int rt){
    tree[rt].lm=tree[rt<<1].lm;
    if(tree[rt].lm==len-(len>>1)){
        tree[rt].lm+=tree[rt<<1|1].lm;
    }
    tree[rt].rm=tree[rt<<1|1].rm;
    if(tree[rt].rm==(len>>1)){
        tree[rt].rm+=tree[rt<<1].rm;
    }
    tree[rt].len=max(tree[rt<<1].rm+tree[rt<<1|1].lm,max(tree[rt<<1].len,tree[rt<<1|1].len));
}
void pushdown(int len,int rt){
    if(tree[rt].cov!=-1){
        tree[rt<<1].cov=tree[rt<<1|1].cov=tree[rt].cov;
        tree[rt<<1].lm=tree[rt<<1].rm=tree[rt<<1].len=tree[rt].cov?0:(len-(len>>1));
        tree[rt<<1|1].lm=tree[rt<<1|1].rm=tree[rt<<1|1].len=tree[rt].cov?0:(len>>1);
        tree[rt].cov=-1;
    }
}
void build(int l,int r,int rt){
    tree[rt].cov=-1;
    tree[rt].lm=tree[rt].rm=tree[rt].len=r-l+1;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
}
void update(int L,int R,int val,int l,int r,int rt){
    if(L<=l&&R>=r){
        tree[rt].cov=val;
        tree[rt].lm=tree[rt].rm=tree[rt].len=val?0:(r-l+1);
        return;
    }
    int mid=(l+r)>>1;
    pushdown(r-l+1,rt);
    if(L<=mid) update(L,R,val,l,mid,rt<<1);
    if(R>mid) update(L,R,val,mid+1,r,rt<<1|1);
    pushup(r-l+1,rt);
}
int query(int w,int l,int r,int rt){
    if(l==r)return 1;
    pushdown(r-l+1,rt);
    int mid=(l+r)>>1;
    if(tree[rt<<1].len>=w) return query(w,l,mid,rt<<1);
    else if(tree[rt<<1].rm+tree[rt<<1|1].lm>=w) return mid-tree[rt<<1].rm+1;
    else return query(w,mid+1,r,rt<<1|1);
}

int main(){
    scanf("%d%d",&n,&m);
    build(1,n,1);
    while(m--){
        int op,x,cnt,ans;
        scanf("%d",&op);
        if(op==1){
            scanf("%d",&cnt);
            if(tree[1].len<cnt) ans=0;
            else ans=query(cnt,1,n,1);
            printf("%d\n",ans);
            if(ans>0) 
                update(ans,ans+cnt-1,1,1,n,1);
        }else{
            scanf("%d%d",&x,&cnt);
            update(x,x+cnt-1,0,1,n,1);
        }
    }
    return 0;
}

 

posted @ 2019-10-14 19:29  两点够吗  阅读(150)  评论(0编辑  收藏  举报