POJ 3667 HOTEL 题解报告

调了半天终于弄出来了,不说别的,开始正题。
题目大意如此:
一行给出n,m(都不超过50000)
n表示区间长度,m表示操作数目。
然后是m行:
分别有两个操作:
for example
一:1 2表示输出最靠左的一段长度为2的连续区间的左端点,并且该区间被占,不可再被使用。
二:2 3 4 表示从端点3往右的4个单位的区间被清空。
样例
IN PUT:
10 6
1 3
1 3
1 3
1 3
2 5 5
1 6
OUT PUT:
1
4
7
0
5
题目要求十分简单, 并且我们可以清楚地知道这是一道数据结构题。
这道题我们可以用线段树来解决。
具体思路如下:
我们的节点存储三个数据:llen表示该区间最左的一段连续区间长度,rlen表示该区间最右的一段连续区间长度,len表示该区间内最长的一段连续区间长度。
举例:0表示未占,1表示占
011111 它的llen就是0,rlen就是5,len就是5。
这样我们就可以快速的查询了。
线段树一个基本的性质就是要满足区间可以合并相加。
我们这样存储那么合并区间可以分为如下几个状态。

void pushup( int lf, int rg ) {
    int mid = (lf + rg) >> 1;
    llen = ls->llen;
    rlen = rs->rlen;
    if ( llen == (mid-lf+1) ) llen += rs->llen;
    if ( rlen == (rg-mid) ) rlen += ls->rlen;
    len = max(ls->rlen+rs->llen, max(ls->len,rs->len) );
}

注意:
根节点的llen如果左儿子全部可以使用那么还要加上右儿子的左部分
根节点的rlen同理可得。
查询时:我们判断左儿子的长度len是不是大于要求如果大于就在左儿子那边找,否则就判断左儿子的rlen加右儿子的llen是不是大于要求,否则就在右儿子找。
具体程序如下:

//
//  main.cpp
//  POJ 3667 Hotel
//
//  Created by apple on 17/3/21.
//  Copyright © 2017年 apple. All rights reserved.
//
//  Memory: 4864K       Time: 610MS
//  Language: C++       Result: Accepted

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 50005;
int n, m, q, x, y;
struct Node{
    int llen, rlen, len, lazy;
    Node *ls, *rs;
    Node() {
        ls = rs = NULL;
    }
    void pushdown( int lf, int rg ) {
        if ( lazy == 1 || lazy == 0 ) {
            int mid = (lf + rg) >> 1;
            ls->llen = ls->rlen = ls->len = lazy*(mid-lf+1);
            rs->rlen = rs->llen = rs->len = lazy*(rg-mid);
            ls->lazy = rs->lazy = lazy;
            lazy = -1;
        }
    }
    void pushup( int lf, int rg ) {
        int mid = (lf + rg) >> 1;
        llen = ls->llen;
        rlen = rs->rlen;
        if ( llen == (mid-lf+1) ) llen += rs->llen;
        if ( rlen == (rg-mid) ) rlen += ls->rlen;
        len = max(ls->rlen+rs->llen, max(ls->len,rs->len) );
    }
};
Node pool[N * 4], *tail = pool, *root;
Node *build(int lf, int rg) {
    Node *nd = ++tail;
    if ( lf == rg) {
        nd->llen = nd->rlen = nd->len = 1;
        nd->lazy = -1;
    }
    else {
        int mid = (lf + rg) >> 1;
        nd->ls = build(lf, mid);
        nd->rs = build(mid+1, rg);
        nd->llen = nd->rlen = nd->len = nd->ls->llen + nd->rs->llen;
        nd->lazy = -1;
    }
    return nd;
}
int query(Node *nd, int lf, int rg, int len) {
    if ( lf == rg ) return lf;
    nd->pushdown(lf, rg);
    int mid = (lf + rg) >> 1;
    if ( nd->ls->len >= len ) return query(nd->ls, lf, mid, len);
    else if ( nd->ls->rlen + nd->rs->llen >= len ) return mid-nd->ls->rlen+1;
    else return query(nd->rs, mid+1, rg, len);
}
void modify( Node *nd, int lf, int rg, int L, int R, int val ) {
    if ( L <= lf && rg <= R ) {
        nd->llen = nd->rlen = nd->len = val*(rg-lf+1);
        nd->lazy = val;
        return;
    }
    nd->pushdown(lf, rg);
    int mid = (lf + rg) >> 1;
    if ( L <= mid ) modify(nd->ls, lf, mid, L, R, val);
    if ( R > mid ) modify(nd->rs, mid+1, rg, L, R, val);
    nd->pushup(lf, rg);
}
int main() {
    scanf( "%d%d", &n, &m );
    root = build(1, n);
    for ( int i = 1; i <= m; i++ ) {
        scanf( "%d", &q );
        if ( q == 1 ) {
            scanf( "%d", &x ); int pos;
            if ( root->len < x ) printf( "0\n" );
            else {
                pos = query( root, 1, n, x );
                printf( "%d\n", pos );
                modify( root , 1, n, pos, pos+x-1, 0 );
            }
        }
        else {
            scanf( "%d%d", &x, &y );
            modify( root, 1, n, x, x+y-1, 1 );
        }
    }
    return 0;
}

完毕!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值