第三届河南省程序设计大赛-NYOJ-250-ROOM ASSIGNATION

ROOM ASSIGNATION
时间限制:1000 ms | 内存限制:65535 KB
难度:4
描述
The “cows” are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Street as their vacation residence. This immense hotel has N (1 <= N <= 50,000) rooms all located on the same side of an extremely long hallway (all the better to see the lake, of course).

The “cows” and other visitors arrive in groups of size D_i (1 <= D_i <= N) and approach the front desk to check in. Each group i requests a set of D_i contiguous rooms from Canmuu, the moose staffing the counter. He assigns them some set of consecutive room numbers r..r+D_i-1 if they are available or, if no contiguous set of rooms is available, politely suggests alternate lodging. Canmuu always chooses the value of r to be the smallest possible.

Visitors also depart the hotel from groups of contiguous rooms. Checkout i has the parameters X_i and D_i which specify the vacating of rooms X_i…X_i+D_i-1 (1 <= X_i <= N-D_i+1). Some (or all) of those rooms might be empty before the checkout.

Your job is to assist Canmuu by processing M (1 <= M < 50,000) checkin/checkout requests. The hotel is initially unoccupied.

输入
There are multi test cases.EOF will terminate the input.
Line 1: Two space-separated integers: N and M
Lines 2…M+1: Line i+1 contains request expressed as one of two possible formats:
(a) Two space separated integers representing a check-in request: 1 and D_i
(b) Three space-separated integers representing a check-out: 2, X_i, and D_i
输出
Lines 1…..: For each check-in request, output a single line with a single integer r, the
first room in the contiguous sequence of rooms to be occupied. If the request
cannot be satisfied, output 0.
样例输入
10 6
1 3
1 3
1 3
1 3
2 5 5
1 6
样例输出
1
4
7
0
5

比较复杂的线段树
已无力写思路,表示注释比代码还多

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=50005;//最大房间数量
int N;//房间数量
int M;//指令数量
struct node
{
    int left;//左端点
    int right;//右端点
    int is_free;//记录当前区间内房间状态
    int num;//区间内最大连续房间数
    int left_num;//区间内从左端点往右最大房间数
    int right_num;//区间内从右端点往左最大房间数
} Tree[maxn*4]; //线段树数组
void Build(int root,int left,int right)//传入建树的根节点和根节点的左右区间
{
    Tree[root].left=left;
    Tree[root].right=right;
    Tree[root].is_free=0;//初始化当前区间有空余房间
    Tree[root].num=Tree[root].left_num=Tree[root].right_num=right-left+1;//这三个数值初始化都相同
    if(left<right)//如果这不是最底层,就接着建树
    {
        int mid=(left+right)>>1;//取当前区间的左右端点
        Build(root<<1,left,mid);//建立左子叶
        Build(root<<1|1,mid+1,right);//建立右子叶
    }
}
int Query(int root,int num_num)//传入根节点和需要入住的人数,返回入住的首个房间序号
{
    if(Tree[root].num<num_num)//如果当前区间内最大连续空房间数不足
        return 0;//直接返回0
    if(Tree[root].left_num>=num_num)//如果当前区间左端点开始连续的空房间数量足够
        return Tree[root].left;//返回左端点坐标
    if(Tree[root<<1].num>=num_num)//如果左子叶区间内有满足条件的连续房间数
        return Query(root<<1,num_num);//递归查询左子叶
    else if(Tree[root<<1].right_num+Tree[root<<1|1].left_num>=num_num)//如果左子叶从右端往左的连续房间数,加上右子叶从左端往右的连续房间数,可以满足连续入住房间数量
        return Tree[root<<1].right-Tree[root<<1].right_num+1;//返回左子叶右端点序号减去,左子叶从右端点往左的连续房间数并加一
    else
        return Query(root<<1|1,num_num);//去右区间找
}
void Update(int root,int left,int right,int flag)//传入根节点,待更新区间,flag==1?更新为已入住:更新为退房
{
    if(Tree[root].left==left&&Tree[root].right==right)
    {
        Tree[root].is_free=flag;//记录当前区间房间状态
        if(flag==1)//更新区间为已入住
            Tree[root].left_num=Tree[root].right_num=Tree[root].num=0;//更新当前区间为已入住
        else
            Tree[root].left_num=Tree[root].right_num=Tree[root].right-Tree[root].left+1;//更新当前区间为退房
    }
    else if(Tree[root].left<Tree[root].right)//当前不是最底层区间,就继续递归更新
    {
        //接下来是数据下沉
        if(Tree[root].is_free==1)//如果当前区间为已入住
        {
            Tree[root<<1].is_free=Tree[root<<1|1].is_free=1;//那它的左右子叶一定也是已入住
            Tree[root<<1].left_num=Tree[root<<1].right_num=Tree[root<<1].num=0;//左右子叶空余房间数量清零
            Tree[root<<1|1].left_num=Tree[root<<1|1].right_num=Tree[root<<1|1].num=0;//这是右子叶
        }
        if(Tree[root].is_free==0)//如果当前区间更新为已退房
        {
            Tree[root<<1].is_free=Tree[root<<1|1].is_free=0;//那它的左右子叶一定也是已退房
            Tree[root<<1].left_num=Tree[root<<1].right_num=Tree[root<<1].num=Tree[root<<1].right-Tree[root<<1].left+1;//左右子叶左右端点出发的连续空房间数量就是区间内房间总数
            Tree[root<<1|1].left_num=Tree[root<<1|1].right_num=Tree[root<<1|1].num=Tree[root<<1|1].right-Tree[root<<1|1].left+1;//注释同上
        }
        int mid=(Tree[root].left+Tree[root].right)>>1;//取区间中点
        if(mid>=right)//如果待更新区间完全在当前区间左子叶部分
            Update(root<<1,left,right,flag);//更新左子叶
        else if(mid<left)//如果待更新区间完全在当前区间右子叶部分
            Update(root<<1|1,left,right,flag);//这一步可能有错
        else//如果待更新区间横跨当前区间左右部分
        {
            Update(root<<1,left,mid,flag);//更新左子叶
            Update(root<<1|1,mid+1,right,flag);//更新右子叶
        }
        //接下来是数据上推
        Tree[root].left_num=Tree[root<<1].left_num;
        Tree[root].right_num=Tree[root<<1|1].right_num;
        if(Tree[root<<1].is_free==0)//如果左子叶区间为已退房,则左子叶整个区间房间都是空的
            Tree[root].left_num+=Tree[root<<1|1].left_num;//当前区间左端点往右连续空房间数,还要加上右区间左端点往右连续空房间数
        if(Tree[root<<1|1].is_free==0)//如果右子叶区间为已退房,则右子叶整个区间都是空的
            Tree[root].right_num+=Tree[root<<1].right_num;//当前区间右端点往左连续空房间数,还要加上左区间右端点往左连续空房间数
        Tree[root].num=max(Tree[root<<1].num,Tree[root<<1|1].num);//当前区间最大连续空房间数量从左右子叶中取最大值
        Tree[root].num=max(Tree[root].num,Tree[root<<1].right_num+Tree[root<<1|1].left_num);//当前区间最大连续空房间数量,取自身和左子叶从右端往左连续空房间数量加上右子叶从左端往右连续空房间数量
        if(Tree[root<<1].is_free==Tree[root<<1|1].is_free)//如果左右子叶区间状态相同
            Tree[root].is_free=Tree[root<<1].is_free;
        else//左右子叶区间状态不同
            Tree[root].is_free=-1;//当前区间状态标记为-1
    }
}
int main()
{
    while(~scanf("%d%d",&N,&M))
    {
        int flag;//为1时,入住,为2时,退房
        int star_num;
        int num_num;
        Build(1,1,N);//建立线段树
        while(M--)//M组输入
        {
            scanf("%d",&flag);
            if(flag==1)//查询入住左端点房间序号
            {
                scanf("%d",&num_num);
                int point_num=Query(1,num_num);
                printf("%d\n",point_num);
                if(point_num!=0)//更新入住
                    Update(1,point_num,point_num+num_num-1,1);//最后一个1,代表此段区间需要被入住
                //这里还缺少再次更新
            }
            else//更新退房
            {
                scanf("%d%d",&star_num,&num_num);
                Update(1,star_num,star_num+num_num-1,0);//最后一个0,代表此段区间需要被清空
            }
        }
    }
    return 0;
}

你可能感兴趣的:(线段树)