Hotel 旅馆

 感觉还是比较值得记录了,当时好像只有我和joke用线段树改出来了,其他人都是暴力

//T3  Hotel 旅馆
//我目前有个思路,差分维护树状数组
//这个区间和为零,那说明全是空的
//退房就减去 试试 关键退得时候可能有一些就是零,你还不能直接减
//找空房间也麻烦啊
//woc 找空房间 山海经!!!????? 好家伙 
//半小时能写完就写 
//我果然写不完,给T1打表去;
//这个根据题面,按照我的感觉跟山海经还不一样,山海经重点在
//pushup里,这个重点在延迟标记的下放判断里 
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int mx=500000+100;
int n,m;
struct Node{
    int len;//原本长度
    int mx;//最大空房间
    int lmx;//左端开始最大空 
    int rmx;//右端开始最大空 
    int lazy;//住还是清 
}t[mx*5];
void Pushup(int k){
    if(t[k<<1].len==t[k<<1].mx){
        t[k].lmx=t[k<<1].len+t[k<<1|1].lmx;
    }
    else t[k].lmx=t[k<<1].lmx;
    if(t[k<<1|1].len==t[k<<1|1].mx){
        t[k].rmx=t[k<<1|1].len+t[k<<1].rmx;
    }
    else t[k].rmx=t[k<<1|1].rmx;
    //左右的sum 和中间 
    t[k].mx=max(t[k<<1].mx,max(t[k<<1|1].mx,t[k<<1].rmx+t[k<<1|1].lmx));    
}
void Pushdown(int k){
    if(t[k].lazy==-1){
        t[k].lazy=0;
        t[k<<1].lazy=-1;
        t[k<<1|1].lazy=-1;
        t[k<<1].mx=t[k<<1].mx=t[k<<1].lmx=t[k<<1].rmx=t[k<<1].len;
        t[k<<1|1].mx=t[k<<1|1].mx=t[k<<1|1].lmx=t[k<<1|1].rmx=t[k<<1|1].len;
    }
    else if(t[k].lazy==1){
        t[k].lazy=0;
        t[k<<1].lazy=1;
        t[k<<1|1].lazy=1;
        t[k<<1].mx=t[k<<1].mx=t[k<<1].lmx=t[k<<1].rmx=0;
        t[k<<1|1].mx=t[k<<1|1].mx=t[k<<1|1].lmx=t[k<<1|1].rmx=0;
    }
}
void updata(int l,int r,int L,int R,int k,int flag){
    Pushdown(k);
//    printf("l=%d r=%d L=%d R=%d k=%d flag=%d t[%d].mx=%d\n",l,r,L,R,k,flag,k,t[k].mx);
    //l L这两组传反了 
    if(L<=l && R>=r){
        if(flag==-1){
            t[k].lazy=-1;
            t[k].mx=t[k].mx=t[k].lmx=t[k].rmx=t[k].len;
        }
        else {
            t[k].lazy=1;
            t[k].mx=t[k].mx=t[k].lmx=t[k].rmx=0;
        }
    }
    else {
        int mid=(l+r)/2;
        if(L<=mid){
            updata(l,mid,L,R,k<<1,flag);
        }
        if(R>mid){
            updata(mid+1,r,L,R,k<<1|1,flag);
            //这里的k<<1|1写成了k<<1 
        }
        Pushup(k);
    }
}
int getleft(int d,int l,int r,int k){
    Pushdown(k);
    //printf("l=%d r=%d\n",l,r);
    if(l==r)return l;
    int mid=(l+r)/2;
    if(t[k<<1].mx>=d){
    //    printf("1k kkkkkkkk\n");
        return getleft(d,l,mid,k<<1);
    }
    //不用else 我直接return了 
    if(t[k<<1].rmx+t[k<<1|1].lmx>=d){
    //    printf("2k kkkkkkkk\n");
        return mid-t[k<<1].rmx+1; 
        //如果是在中间,那么左端点直接就出来了,不用管了 
    }
    if(t[k<<1|1].mx>=d){
//        printf("3k kkkkkkkk\n");
        return getleft(d,mid+1,r,k<<1|1);
    }
}
void Build(int l,int r,int k){
//    printf("kkkkkkkkkkkkk\n");
    t[k].lazy=0;//这可千万别忘了,随机值 
    t[k].len=t[k].mx=t[k].lmx=t[k].rmx=r-l+1;
//    printf("t[%d].len=%d\n",k,t[k].len);
    if(l==r)return ;
    
    int mid=(l+r)/2;
    Build(l,mid,k<<1);
    Build(mid+1,r,k<<1|1); 
}
void Solve(){
    scanf("%d%d",&n,&m);
    Build(1,n,1); 
    for(int i=1;i<=m;++i){
        int x;
        scanf("%d",&x);
        if(x==1){
            int d;
            scanf("%d",&d);
            int ans=0;
            if(t[1].mx<d){
    //            printf("t[1].mx=%d d=%d\n",t[1].mx,d);
                ans=0;
            } 
            else{
                ans=getleft(d,1,n,1);
        //        printf("ans=%d\n",ans);
                updata(1,n,ans,ans+d-1,1,1);
            }
            for(int i=1;i<=25;++i){
        //        printf("t[%d].mx=%d\n",i,t[i].mx);
            }
            printf("%d\n",ans);
        }
        else {
            int d1,d2;
            scanf("%d%d",&d1,&d2);
            updata(1,n,d1,d2+d1-1,1,-1);
            //这里也是反了没改  5 5 的意思是5+5-1 你读题啊啊啊 
        }
    } 
}
int main(){
    freopen("hotel.in","r",stdin);
    freopen("hotel.out","w",stdout); 
    Solve();
    return 0;
} 
View Code

 

posted @ 2022-02-21 10:17  SMTwy  阅读(63)  评论(0编辑  收藏  举报