takapt0226's diary

競技プログラミングのことを書きます

POJ 3667 Hotel

解法

SegTree。区間は以下の3つの情報を持つ必要がある。

  • 区間内で最大の連続した空きスペース
  • 区間の左端から連続した空きスペース
  • 区間の右端から連続した空きスペース

(実装では、その区間は完全に空きであるか(empty)を持っているが補助的なもの。)

この問題では、区間に対する操作が必要なので、遅延評価をする必要がある。
遅延評価についてわからない人はkyuridenamida先生による解説を読もう
http://d.hatena.ne.jp/kyuridenamida/20121114/1352835261

ソースコード

class HotelSegTree
{
private:
    struct Seg
    {
	bool empty;
	int max_space;
	int left_space;
	int right_space;
	int lazy;
	Seg()
	    : empty(false), max_space(0),
	      left_space(0), right_space(0),
	      lazy(-1)
	{
	}
    };

    vector<Seg> seg;
    int SIZE;

    static const int IN = 1, OUT = 0;
    void update(int a, int b, int ope, int k, int l, int r)
    {
	const int space = r - l;
	const int mid = (l + r) / 2;
	const int lk = 2 * k + 1, rk = 2 * k + 2;

	if (seg[k].lazy != -1)
	{
	    int lazy_ope = seg[k].lazy;
	    seg[k].lazy = -1;
	    update(l, r, lazy_ope, k, l, r);
	}

	if (b <= l || r <= a || space == 0)
	    return;

	if (a <= l && r <= b)
	{
	    seg[k].max_space = seg[k].left_space = seg[k].right_space
		= ope == OUT ? space : 0;
	    seg[k].empty = ope == OUT;

	    if (k < SIZE)
		seg[lk].lazy = seg[rk].lazy = ope;
	}
	else
	{
	    update(a, b, ope, lk, l, mid);
	    update(a, b, ope, rk, mid, r);

	    const int cat_space = seg[lk].right_space + seg[rk].left_space;
	    seg[k].max_space = max(cat_space, max(seg[lk].max_space, seg[rk].max_space));
	    seg[k].empty = seg[k].max_space == space;

	    seg[k].left_space = seg[lk].left_space;
	    if (seg[lk].empty)
		seg[k].left_space += seg[rk].left_space;

	    seg[k].right_space = seg[rk].right_space;
	    if (seg[rk].empty)
		seg[k].right_space += seg[lk].right_space;
	}
    }

    int find(int need_space, int k, int l, int r)
    {
	if (seg[k].left_space >= need_space)
	    return l;

	int mid = (l + r) / 2;
	int lk = 2 * k + 1, rk = 2 * k + 2;
	if (seg[lk].max_space >= need_space)
	    return find(need_space, lk, l, mid);
	else if (seg[lk].right_space + seg[rk].left_space >= need_space)
	    return mid - seg[lk].right_space;
	else
	    return find(need_space, rk, mid, r);
    }

public:
    HotelSegTree(int n)
    {
	SIZE = 1;
	while (SIZE < n)
	    SIZE *= 2;
	seg.resize(2 * SIZE);
    }

    void out(int l, int r)
    {
	update(l, r, OUT, 0, 0, SIZE);
    }

    void in(int l, int r)
    {
	update(l, r, IN, 0, 0, SIZE);
    }

    int find(int need_space)
    {
	if (seg[0].max_space < need_space)
	    return -1;
	else
	    return find(need_space, 0, 0, SIZE);
    }
};
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);

    HotelSegTree segtree(n);
    segtree.out(0, n);
    while (m--)
    {
	int q;
	scanf("%d", &q);
	if (q == 1)
	{
	    int d;
	    scanf("%d", &d);

	    int k = segtree.find(d);
	    if (k == -1)
		puts("0");
	    else
	    {
		printf("%d\n", k + 1);
		segtree.in(k, k + d);
	    }
	}
	else
	{
	    int x, d;
	    scanf("%d%d", &x, &d);
	    --x;

	    segtree.out(x, x + d);
	}
    }
}