/*
區間線段樹 區間合并
題意:Hotel有N房間,兩種操作:一種checkin(x),某個團的x個人要住連續的x間房間(k,k+1,..,k+x-1),若有合適的房間則輸出最小房間編號k,否>則0,表示謝絕這個團的生意。另一種checkout(x,y),原住x,x+1,..,x+y-1的人要離開,則這些房間就空了出來,這裡面可能有一些原本就是空的。
思路:經典區間線段樹。維護這麼幾個值:
Seg_tree_Node {
int l, r;
int l_rest, r_rest; 以l為起點的連續空餘房間數,以r為終點的連續空餘房間數
int max, max_pos; 區間最多的連續空餘房間數,以及對應的最小編號。
int add; for lazy.._zZ
}
Query的順序為:<1>有合適的房間?f[1].max >= need ?
<1.5> 如果f[u].max == need 則直接返回f[u].max_pos
<2>u的左節點l_child, l_child.max >= need ? 是就進左節點
<3>u的左右節點交界處?
<4>上面都不行的話就進右節點吧
養成了風格,當有lazy來時如果要保持當前節點的屬性為最新,則需要更新當前節點屬性,我用put_self()。
下降lazy用put_down(),有時在Update()時下降,有時在Query()時也要下降。
Update的最後總會有個put_up()
*/
#include <stdio.h>#define debug printf("!\n")#define MAXN 50005 #define MID(x, y) (((x)+(y)) >> 1LL)#define L(x) ((x)<<1LL)#define R(x) (((x)<<1LL)|1LL)struct Node { int l, r, l_rest, r_rest, max, max_pos, add;} f[MAXN << 2];void Update(int, int, int, int);void put_up(int u){ Node & a = f[u]; Node & ll = f[L(u)]; Node & rr = f[R(u)]; if(ll.max >= rr.max) { a.max = ll.max; a.max_pos = ll.max_pos; } else { a.max = rr.max; a.max_pos = rr.max_pos; } a.l_rest = ll.l_rest; //小錯誤大煩惱...因為一個字母拼錯了,debug了好久! a.r_rest = rr.r_rest; if(ll.r_rest != 0 && rr.l_rest != 0) { if(a.max < ll.r_rest + rr.l_rest || (a.max == ll.r_rest + rr.l_rest && a.max_pos > ll.r - ll.r_rest + 1)) { a.max = ll.r_rest + rr.l_rest; a.max_pos = ll.r - ll.r_rest + 1; } if(ll.l_rest == ll.r - ll.l + 1) a.l_rest = ll.l_rest + rr.l_rest; if(rr.r_rest == rr.r - rr.l + 1) a.r_rest = rr.r_rest + ll.r_rest; }}void build(int u, int l, int r){ f[u].l = l, f[u].r = r, f[u].add = 0; if(l == r) { f[u].max = f[u].l_rest = f[u].r_rest = 1; f[u].max_pos = l; return ; } int mid = MID(l, r); build(L(u), l, mid); build(R(u), mid+1, r); put_up(u);}void put_down(int u){ int mid = MID(f[u].l, f[u].r); Update(L(u), f[u].l, mid, f[u].add); Update(R(u), mid+1, f[u].r, f[u].add); f[u].add = 0;}void put_self(int u){ Node & a = f[u]; a.max_pos = a.l; a.max = a.l_rest = a.r_rest = (a.r - a.l + 1) * (int)(a.add == 1);}void Update(int u, int l, int r, int add){ if(l == f[u].l && f[u].r == r) { f[u].add = add ; put_self(u); return ; } if(f[u].add) put_down(u); int mid = MID(f[u].l , f[u].r); if(r <= mid) Update(L(u), l, r, add); else if(mid < l) Update(R(u), l, r, add); else Update(L(u), l, mid, add), Update(R(u), mid+1, r, add); put_up(u);}int Query(int u, int need){ Node & ll = f[L(u)]; Node & rr = f[R(u)]; if(f[u].max == need) return f[u].max_pos; //MARK 呆會兒看看max的更新 //感覺這句不影響吧.. if(f[u].add) put_down(u); if(ll.max >= need) return Query(L(u), need); else if(ll.r_rest + rr.l_rest >= need) return ll.r - ll.r_rest + 1; else return Query(R(u), need);}int main(){ int query, n, op, need, l, r; scanf("%d%d", &n, &query); build(1, 1, n); while(query--) { scanf("%d", &op); if(op == 1) { scanf("%d", &need); if(f[1].max < need) printf("0\n"); else { int result = Query(1, need); if(result) Update(1, result, result+need-1, 2); printf("%d\n", result); } } else { scanf("%d%d", &l, &r); Update(1, l, r+l-1, 1); } } return 0;}