poj3667

链接:点击打开链接

题意:有N个连续的空房间,分别编号1~N,M条指令,指令分为两种,分别为1 D和2 X D,第一种指令输出是否有D个连续的空房间,如果有则输出最靠左的第一个房间编号,否则则输出0,第二种则将从X开始D个房间清空

代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
const int SIZE=50005;
int sum[SIZE<<2],lsum[SIZE<<2],rsum[SIZE<<2];           //sum表示当前节点所代表的区间最长连续空位
int add[SIZE<<2];                                       //lsum表示当前节点所代表的区间从左端起的最长连续空位
void pushdown(int rt,int m){                            //rsum表示当前节点所代表的区间从右端起的最长连续空位
    if(add[rt]!=-1){
        add[rt<<1]=add[rt<<1|1]=add[rt];
        sum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=add[rt]?0:(m-(m>>1));
        sum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=add[rt]?0:(m>>1);
        add[rt]=-1;
    }
}                                                       //懒惰标记跟区间更新几乎是一样的    
void pushup(int rt,int m){
    lsum[rt]=lsum[rt<<1];
    rsum[rt]=rsum[rt<<1|1];
    if(lsum[rt]==(m-(m>>1)))
    lsum[rt]+=lsum[rt<<1|1];
    if(rsum[rt]==(m>>1))
    rsum[rt]+=rsum[rt<<1];
    sum[rt]=max(lsum[rt<<1|1]+rsum[rt<<1],max(sum[rt<<1],sum[rt<<1|1]));
}                                                       //根据lsum和rsum判断sum
void build(int l,int r,int rt){
    int m;
    sum[rt]=lsum[rt]=rsum[rt]=r-l+1;
    add[rt]=-1;
    if(l==r)
    return;
    m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
}
void update(int L,int R,int c,int l,int r,int rt){
    int m;
    if(L<=l&&r<=R){
        sum[rt]=lsum[rt]=rsum[rt]=c?0:r-l+1;
        add[rt]=c;
        return;
    }
    pushdown(rt,r-l+1);
    m=(l+r)>>1;
    if(L<=m)
    update(L,R,c,l,m,rt<<1);
    if(R>m)
    update(L,R,c,m+1,r,rt<<1|1);
    pushup(rt,r-l+1);
}                                                       //建树和更新和成段更新也几乎是一样的
int query(int w,int l,int r,int rt){
    int m;
    if(l==r)
    return l;
    pushdown(rt,r-l+1);
    m=(r+l)>>1;
    if(sum[rt<<1]>=w)                                   //因为题目要求尽可能靠左,因此先查询左区间
    return query(w,l,m,rt<<1);
    else if(lsum[rt<<1|1]+rsum[rt<<1]>=w)               //然后左右区间相连
    return m-rsum[rt<<1]+1;
    return query(w,m+1,r,rt<<1|1);                      //最后查询右区间
}                                                           
int main(){
    int n,m,i,j,a,b,c,tmp;
    while(scanf("%d%d",&n,&m)!=EOF){
        build(1,n,1);
        while(m--){
            scanf("%d",&c);
            if(c==1){
                scanf("%d",&a);
                if(sum[1]<a){
                    puts("0");
                    continue;
                }                                       //没有时输出0    
                tmp=query(a,1,n,1);
                printf("%d\n",tmp);
                update(tmp,tmp+a-1,1,1,n,1);
            }
            else{
                scanf("%d%d",&a,&b);
                update(a,a+b-1,0,1,n,1);
            }
        }
    }
    return 0;
}


 

你可能感兴趣的:(poj3667)