POJ3667线段树区间合并

POJ3667Hotel要求支持两种操作:成段分配与成段回收。

/*
   1 a:找一段空间有连续a个空,分配出去
   2 a b: 从a开始的b个位置回收
*/

#include <stdio.h>

int const SIZE = 50010;

//ST[t]表示t节点中最长的可用空间
int ST[SIZE<<2];

//Start[t]表示最长可用空间的起点
int Start[SIZE<<2];

//Front[t]表示t的最左边连续区间的长度
int Front[SIZE<<2];

//Back[t]表示t的最右边连续区间的长度
int Back[SIZE<<2];
//
int Lazy[SIZE<<2];

inline int lson(int t){return t<<1;}
inline int rson(int t){return lson(t)|1;}

inline void _pushUp(int t,int s,int e){
    int left = ST[lson(t)];
    int right = ST[rson(t)];
    int mid = Back[lson(t)] + Front[rson(t)];

    int const m = ( s + e ) >> 1;
    if(left>=mid&&left>=right){
        ST[t] = left;
        Start[t] = Start[lson(t)];
    }else if(mid>left&&mid>=right){
        ST[t] = mid;
        Start[t] = m - Back[lson(t)] + 1;
    }else{
        ST[t] = right;
        Start[t] = Start[rson(t)];
    }

    Front[t] = Front[lson(t)];
    if(m-s+1==Front[lson(t)]) Front[t] += Front[rson(t)];

    Back[t] = Back[rson(t)];
    if(e-m==Back[rson(t)]) Back[t] += Back[lson(t)];
}

inline void _pushDown(int t,int s,int e){
    if(1==Lazy[t]){//1表示分配
        int son = lson(t);
        ST[son] = Start[son] = Front[son] = Back[son] = 0;//全都分配出去了,空闲长度为0
        Lazy[son] = 1;

        son = rson(t);
        ST[son] = Start[son] = Front[son] = Back[son] = 0;
        Lazy[son] = 1;
    }else if(2==Lazy[t]){//2表示回收
        int const m = ( s + e ) >> 1;
        int son = lson(t);
        ST[son] = Front[son] = Back[son] = m - s + 1;
        Start[son] = s;
        Lazy[son] = 2;

        son = rson(t);
        ST[son] = Front[son] = Back[son] = e - m;
        Start[son] = m + 1;
        Lazy[son] = 2;
    }
    Lazy[t] = 0;
}

void build(int t,int s,int e){
    Lazy[t] = 0;
    if ( s == e ){
        ST[t] = Front[t] = Back[t] = 1;
        Start[t] = s;
        return;
    }

    int const m = ( s + e ) >> 1;
    build(lson(t),s,m);
    build(rson(t),m+1,e);
    _pushUp(t,s,e);
}

//返回有连续length长度空闲空间的最小起始点
int query(int t,int s,int e,int length){
    if(ST[t]<length){
        return 0;
    }else if(ST[t]==length){
        return Start[t];
    }

    _pushDown(t,s,e);
    int const m = ( s + e ) >> 1;
    //左儿子区间有答案
    if(ST[lson(t)]>=length)return query(lson(t),s,m,length);
    //如果答案在左右儿子之间
    if(Back[lson(t)]+Front[rson(t)]>=length) return m - Back[lson(t)] + 1;
    return query(rson(t),m+1,e,length);
}

//op为1表示分配,为2表示回收
//对源数组[a, b]区间做op操作
void modify(int t,int s,int e,int a,int b,int op){
    if(a<=s&&e<=b){
        Lazy[t] = op;
        if(1==op){
            ST[t] = Start[t] = Front[t] = Back[t] = 0;
        }else{
            ST[t] = Front[t] = Back[t] = e - s + 1;
            Start[t] = s;
        }
        return;
    }

    _pushDown(t,s,e);
    int const m = ( s + e ) >> 1;
    if(a<=m)modify(lson(t),s,m,a,b,op);
    if(m<b)modify(rson(t),m+1,e,a,b,op);
    _pushUp(t,s,e);
}

int N,M;
int main(){
    //freopen("1.txt","r",stdin);
    scanf("%d%d",&N,&M);
    build(1,1,N);

    int op,a,b;
    while(M--){
        scanf("%d%d",&op,&a);

        if(1==op){
            int ret = query(1,1,N,a);
            printf("%d\n",ret);
            if(ret){
                b = ret + a - 1;
                modify(1,1,N,ret,b,1);
            }
        }else{
            scanf("%d",&b);
            b = a + b - 1;
            modify(1,1,N,a,b,2);
        }

    }
    return 0;
}

上一篇:[转载]浅谈组策略设置IE受信任站点


下一篇:「Luogu P5826 【模板】子序列自动机」