HDU_2871 Memory Control 线段树

http://acm.hdu.edu.cn/showproblem.php?pid=2871

题意:

内存分配问题,给你一块有N个单元的空白内存和一些内存的操作命令,包括有:

(1)、Reset :清空所有的内存空间;

(2)、New x :申请一块连续长度为x的内存空间,如果不存在这样的分配, 则输出-1 , 如果存在,则输出这块内存的开始地址;

(3)、Free x :如果第x个内存单元所在的点没有被分配,则输出释放失败;如果存在一块内存,则将该内存释放, 并输出该内存的 开始和结束的地址;

(4)、Get x :输出内存快x的开始地址;

思路:

线段树。这是一道比较综合的线段树,需要用到区间合并的线段树操作,因为有New操作, 因此我们需要在没个结点保存max, lmax, rmax 信息, 分别表示该区间的最大空白长度,区间左端点开始i的最长空白长度,右边开始的最长空白长度,这样New操作就可以解决了。接着是Free操作,其实可以将Free操作分解成两部分,第一部分就是先判断x单元是否被使用,如果没被使用就直接输出失败,如果被使用了,只要知道了是那块内存覆盖的就可以求出开始地址和结束地址,对于判断,我们可以利用上面的线段树,对于一段区间,用0表示空白,>0表示相应的块占了内存,<0表示混合区间, 这样就可以在O(logn)的时间内判断出是否被使用,而且如果被使用还可以返回覆盖的块号 ,这样我们可以是先将每个块的开始地址和结束地址以块号为索引存起来, 之后就可以在O(1)的时间内求出开始地址和结束地址了。 至于Get x ,我们可以用一个Vector数组存放每个块的开始地址,然后用一次sort排序就可以在O(1)的时间内求出x块的开始地址了。

代码:

#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
#define LL(a) ( (a)<<1 )
#define RR(a) ( (a)<<1|1 )

const int MAXN = 50010 ;
int N ,M ;
int col[MAXN<<2] , set[MAXN<<2] ;
int tmax[MAXN<<2] , lmax[MAXN<<2] , rmax[MAXN<<2] ;
int s[MAXN],e[MAXN] ;
int ss ,ee ;
vector<int> vv ;

void build(int l, int r, int idx){
    col[idx] = set[idx] = 0 ;
    lmax[idx] = rmax[idx] = tmax[idx] = r - l + 1 ;
    if(l == r)  return ;
    int mid = (l + r)>>1 ;
    build(l ,mid ,LL(idx)) ;
    build(mid+1,r , RR(idx));
}

void PP(int c,  int idx, int len ){
    if( c == 0 ){
        lmax[idx] = rmax[idx] = tmax[idx] = len ;
    }
    else
        lmax[idx] = rmax[idx] = tmax[idx] = 0 ;
}

void down(int l ,int r, int idx){
    int mid = ( l + r ) >> 1 ;
    if( set[idx] ){
        set[ LL(idx) ] = set[ RR(idx) ] = 1 ;
        col[ LL(idx) ] = col[ RR(idx) ] = col[idx] ;
        PP( col[ LL(idx) ] , LL(idx) , mid - l + 1 );
        PP( col[ RR(idx) ] , RR(idx) , r - mid );
        set[idx] = 0 ;
    }
}

int query(int l ,int r , int idx,  int len){
    if( tmax[idx] < len )    return -1 ;
    if( r-l+1 == len ){
        return l ;
    }
    down(l, r , idx );
    int mid = (l + r) >> 1 ;
    if( tmax[ LL(idx) ] >= len ) return query(l , mid , LL(idx) , len );
    else if( rmax[ LL(idx) ]!=0 && rmax[ LL(idx) ] + lmax[ RR(idx) ] >= len){
        return mid + 1 - rmax[ LL(idx) ] ;
    }
    else if( tmax[ RR(idx) ] >= len ){
        return query(mid+1 , r ,RR(idx) , len );
    }
    else    return -1 ;
}

void up(int l ,int r , int idx){
    int mid = (l + r) >> 1 ;
    if( col[ LL(idx) ] == col[ RR(idx) ])
        col[idx] = col[ LL(idx) ] ;
    else
        col[idx] = -1 ;

    lmax[idx] = lmax[ LL(idx) ]  ;
    if( lmax[ LL(idx) ] == mid-l+1 ){
        lmax[idx] = lmax[ LL(idx) ] + lmax[ RR(idx) ] ;
    }
    rmax[idx] = rmax[ RR(idx) ] ;
    if( rmax[ RR(idx) ] == r - mid ){
        rmax[idx] = rmax[ RR(idx) ] + rmax[ LL(idx) ] ;
    }
    tmax[idx] = tmax[ LL(idx) ] ;
    if( tmax[idx] < tmax[ RR(idx) ] )
        tmax[idx] = tmax[ RR(idx) ] ;
    if( rmax[ LL(idx) ] + lmax[ RR(idx) ] > tmax[idx])
        tmax[idx] = rmax[ LL(idx) ] + lmax[ RR(idx) ] ;
}

void update(int l ,int r, int idx, int a , int b , int v){
    if(l==a && r==b){
        col[idx] = v ;
        set[idx] = 1 ;
        PP( col[idx] ,idx, r-l+1);
        return ;
    }
    down(l ,r , idx);
    int mid = (l + r) >> 1 ;
    if( b<=mid )    update( l ,mid , LL(idx) , a,  b, v );
    else if( mid<a )    update( mid+1 ,r, RR(idx) ,a, b, v);
    else{
        update(l, mid, LL(idx), a, mid , v);
        update(mid+1 ,r, RR(idx) , mid+1, b , v );
    }
    up(l, r, idx ) ;
}

int query_id(int l ,int r, int idx ,int pos ){
    if(l == r){
        return col[idx] ;
    }
    down(l , r, idx);
    int mid = (l + r) >> 1 ;
    if( pos <= mid )    return query_id( l , mid , LL(idx) , pos );
    else                return query_id( mid+1 , r ,RR(idx) ,pos ) ;
    up( l,r ,idx) ;
}
void solve(){
    int a  ;
    char op[10] ;
    vv.clear() ;
    int temp = 1 ;
    for(int i=1;i<=M;i++){
        scanf("%s",op);
        if( op[0]=='N' ){
            //new
            scanf("%d",&a);
            int res = query(1, N ,1 ,a );
            if( res == -1 )
                printf("Reject New\n");
            else{
                printf("New at %d\n",res);
                vv.push_back( res ) ;
                ss = res  ; ee = res + a - 1 ;
                s[ temp ] = ss ; e[ temp ] = ee ;
                update(1 , N ,1 , ss , ee , temp);
                temp++ ;
            }
        }
        else if( op[0] == 'F' ){
            // Free
            scanf("%d",&a);
            int rr = query_id(1 , N ,1 , a) ;
            if( rr == 0 ){
                puts("Reject Free");
            }
            else{
                printf("Free from %d to %d\n",s[rr], e[rr] );
            /*
                sort( vv.begin() , vv.end() );
                vv.erase( lower_bound( vv.begin() , vv.end() ,  s[rr] ) );
            */
                vector<int>::iterator it ;
                for( it=vv.begin() ; it != vv.end() ; it++ ){
                    if( *it == s[rr] ){
                        vv.erase( it );
                        break ;
                    }
                }
                update(1 , N ,1 ,s[rr] ,e[rr], 0 );
            }
        }
        else if( op[0] == 'G'){
            // get
            scanf("%d",&a);
            if( vv.size() < a )
                printf("Reject Get\n");
            else{
                sort( vv.begin() , vv.end() );
                printf("Get at %d\n",vv[a-1]);
            }
        }
        else{
            // Reset
            printf("Reset Now\n");
            update(1 , N , 1 , 1, N , 0 );
            vv.clear() ;
        }
    }
}

int main(){
    while( scanf("%d %d",&N,&M) == 2){
        memset(s , -1, sizeof(s));
        memset(e , -1, sizeof(e));
        build(1, N ,1) ;
        solve() ;
        printf("\n");
    }
    return 0 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值