poj 3667 Hotel
该题是道成段更新,寻找空间(经典类型,求一块满足条件的最左边的空间)
代码的注释比较详细,这里就不多说了。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
class Node
{
public:
int l ,r;
int l_value,r_value,max;
/*l_value从左节点数起的最大连续空闲区间
r_value从右节点起的最大连续空闲区间
max//整个区间的最大连续空闲区间
*/
int cover; //当前区间的占用情况,1表示占用,0表示不占用,-1表示既有占用又有不占用
};
Node tree[250024];
class Tree
{
public:
void Maketree( int l ,int r, int cnt );
void Updata( int l , int r ,int cnt , int num );
int Query( int cnt , int num );
void fun( int cnt );
int Max( int a,int b )
{ return a>b?a:b; }
};
void Tree::Maketree( int l, int r , int cnt )//建树
{
tree[cnt].l = l ;
tree[cnt].r = r;
tree[cnt].l_value = tree[cnt].r_value = tree[cnt].max = r - l +1;
tree[cnt].cover = 0;
if( l == r ) return ;
int mid = ( l + r )>>1;
Maketree( l , mid ,cnt*2 );
Maketree( mid + 1 , r ,cnt*2+1 );
}
void Tree::fun(int cnt)
{
if( tree[cnt].cover == 0 )//如果该点被点被空出来
tree[cnt].l_value = tree[cnt].r_value =tree[cnt].max= tree[cnt].r - tree[cnt].l + 1;
else tree[cnt].l_value = tree[cnt].r_value = tree[cnt].max=0;
}
void Tree::Updata(int l , int r, int cnt ,int num)
{
if( l> tree[cnt].r||r<tree[cnt].l )
return ;
else
{
if( l<=tree[cnt].l&&r>=tree[cnt].r )
{
tree[cnt].cover = num;
fun( cnt );//更新该段区间
return;
}
else
{
if( tree[cnt].cover!=-1 )//向下更新节点
{
tree[cnt*2].cover = tree[cnt*2+1].cover = tree[cnt].cover;
fun( cnt*2 );
fun( cnt*2+1 );
tree[cnt].cover = -1;
}
Updata( l ,r , cnt*2 ,num );
Updata( l , r ,cnt*2 + 1 ,num );
if( tree[cnt*2].cover == tree[cnt*2+1].cover )//由下而上跟新所有信息
tree[cnt].cover = tree[cnt*2].cover;
else tree[cnt].cover = -1 ;
tree[cnt].l_value = tree[cnt*2].l_value + ( tree[cnt*2].cover == 0? tree[cnt*2+1].l_value:0 );
//从左节点起的连续空间,如果做节点是空的代表该节点可以连接右节点的左边的连续空间
tree[cnt].r_value = tree[cnt*2+1].r_value + ( tree[cnt*2+1].cover==0? tree[cnt*2].r_value : 0 );
//从右节点起的连续空间,如果做节点是空的代表该节点可以连接左节点的右边的连续空间
tree[cnt].max = Max( Max(tree[cnt*2].max, tree[cnt*2+1].max ) ,tree[cnt*2].r_value + tree[cnt*2+1].l_value );
//寻找最大的连续空间(左边,中间,右边的比较)
}
}
}
int Tree::Query(int cnt, int num)
{
if( tree[cnt].l_value >= num&&tree[cnt].cover==0 )//左边有num大的连续空间
{
Updata( tree[cnt].l, tree[cnt].l+num-1, 1 , 1 );
return tree[cnt].l;
}
if( tree[ cnt ].cover == 1 ) return 0;
if( tree[cnt].max >= num&&tree[cnt].cover==-1 )//存在这样的空间大于num
{
if( tree[cnt*2].max >= num )//左边有num大的连续空间
return Query( cnt*2 , num );
else
{
if( tree[cnt*2].r_value + tree[cnt*2+1].l_value >= num )//中间有num大的连续空间
{
int t = tree[cnt*2].r - tree[cnt*2].r_value;
Updata( t + 1 ,t+ num , 1 ,1 );
return t+ 1;
}
else return Query( cnt*2+1 , num );//右边有num大的连续空间
}
}
return 0;
}
int main( )
{
int n,m,fornt,num,a;
while( scanf( "%d%d",&n,&m )==2 )
{
Tree e;
e.Maketree( 1 , n , 1 );
while( m-- )
{
scanf( "%d",&a );
if( a == 1 )
{
scanf( "%d",&num );
printf( "%d\n",e.Query( 1 , num ) );
// if( b )
// e.Updata( b , b + num-1 , 1 ,1 );
}
else
{
scanf( "%d%d",&fornt ,&num );
e.Updata( fornt ,fornt+num-1 , 1 ,0 );
}
}
}
return 0;
}

浙公网安备 33010602011771号