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 ;
}