调了半天终于弄出来了,不说别的,开始正题。
题目大意如此:
一行给出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;
}
完毕!