题目链接:http://poj.org/problem?id=3667
题意:有一个hotel有n间房子,现在有2种操作:
1 a,check in,表示入住。需要a间连续的房子。返回尽量靠左的房间编号并更新。
2 a b,check out,从a开始退房,一共退到a+b-1。
seg数组l表示从左边开始数空房子的个数,r表示从右边数空房子的个数,s表示一共最多是有s个连续的空房子。
add作为延迟标记有3种状态:-1表示不操作,0表示退房,1表示入住。
pushUP:向上更新,需要更新seg[rt]的三个值,依据是seg[lrt]和seg[rrt]共计6个值。
由于seg[rt]表示包括了seg[lrt]和seg[rrt]两个区间,那么一开始seg[rt].l=seg[lrt].l,seg[rt].r=seg[rrt].r是木有问题的,接下来要考虑两边合并后seg[lrt]的右和seg[rrt]的左链接起来的情况:
当lrt的左起连续区间和lrt的整个长度相同的时候,说明这一整块都是连续区间,那必然会和rrt的左起最长连续区间连接在一起(当然这里说的连续区间是指的空房子)。所以要在这种情况下更新lrt;同理也要更新rrt。
最后要更新rt的总计最长,即rt左起算最长区间和rt算右起最长区间。但是不要忘记lrt和rrt本身的最长区间seg[lrt].s和seg[rrt].s。
pushDOWN:向下更新,目的是为了传递懒惰标记,这个比较简单。注意好add三个含义就行了,释放的时候需要将节点的三个值都归为下属区间的总长度。
update:很常规。
query:查询的时候尽可能靠左,判断三种情况:当前节点左儿子的最大连续区间大于等于要求区间长度、中间(seg[lrt].r+seg[rrt].l)大于等于要求区间长度、右儿子大于要求区间长度。
左右儿子遍历即可,中间的话长度可以直接得到:mid此时应当作为向左遍历的右终点,但是无法再相左,所以应该是当前节点左儿子的从右计数开始的那段。起始编号即mid-seg[lrt].r+1。
1 #include <algorithm> 2 #include <iostream> 3 #include <iomanip> 4 #include <cstring> 5 #include <climits> 6 #include <complex> 7 #include <cassert> 8 #include <cstdio> 9 #include <bitset> 10 #include <vector> 11 #include <deque> 12 #include <queue> 13 #include <stack> 14 #include <ctime> 15 #include <set> 16 #include <map> 17 #include <cmath> 18 using namespace std; 19 20 #define lrt rt << 1 21 #define rrt rt << 1 | 1 22 const int maxn = 50050; 23 typedef struct Node { 24 int s, l, r; 25 }Node; 26 27 int add[maxn<<2]; 28 Node seg[maxn<<2]; 29 int n, q, cmd; 30 31 void build(int l, int r, int rt) { 32 add[rt] = -1; 33 seg[rt].s = seg[rt].l = seg[rt].r = r - l + 1; 34 if(l == r) return; 35 int mid = (l + r) >> 1; 36 build(l, mid, lrt); 37 build(mid+1, r, rrt); 38 } 39 40 void pushUP(int rt, int len) { 41 seg[rt].l = seg[lrt].l; 42 seg[rt].r = seg[rrt].r; 43 if(seg[rt].l == len - len / 2) seg[rt].l += seg[rrt].l; 44 if(seg[rt].r == len / 2) seg[rt].r += seg[lrt].r; 45 seg[rt].s = max(max(seg[rt].l, seg[rt].r), max(seg[lrt].s, seg[rrt].s)); 46 seg[rt].s = max(seg[rt].s, seg[lrt].r+seg[rrt].l); 47 } 48 49 void pushDOWN(int rt, int len) { 50 if(~add[rt]) { 51 if(add[rt] != 0) { 52 seg[lrt].s = seg[lrt].l = seg[lrt].r = 0; 53 seg[rrt].s = seg[rrt].l = seg[rrt].r = 0; 54 } 55 else { 56 seg[lrt].s = seg[lrt].l = seg[lrt].r = len - len / 2; 57 seg[rrt].s = seg[rrt].l = seg[rrt].r = len / 2; 58 } 59 add[lrt] = add[rrt] = add[rt]; 60 add[rt] = -1; 61 } 62 } 63 64 int query(int pos, int l, int r, int rt) { 65 if(l == r) return 1; 66 pushDOWN(rt, r-l+1); 67 int mid = (l + r) >> 1; 68 if(seg[lrt].s >= pos) return query(pos, l, mid, lrt); 69 else if(seg[lrt].r + seg[rrt].l >= pos) return mid - seg[lrt].r + 1; 70 else return query(pos, mid+1, r, rrt); 71 } 72 73 void update(int L, int R, int c, int l, int r, int rt) { 74 if(L <= l && r <= R) { 75 seg[rt].s = seg[rt].l = seg[rt].r = c ? 0 : r - l + 1; 76 add[rt] = c; 77 return; 78 } 79 pushDOWN(rt, r-l+1); 80 int mid = (l + r) >> 1; 81 if(L <= mid) update(L, R, c, l, mid, lrt); 82 if(mid < R) update(L, R, c, mid+1, r, rrt); 83 pushUP(rt, r-l+1); 84 } 85 86 int main() { 87 // freopen("in", "r", stdin); 88 int a, b; 89 while(~scanf("%d %d", &n, &q)) { 90 build(1, n, 1); 91 for(int i = 0; i < q; i++) { 92 scanf("%d", &cmd); 93 if(cmd == 1) { 94 scanf("%d", &a); 95 if(a > seg[1].s) { 96 puts("0"); 97 continue; 98 } 99 b = query(a, 1, n, 1); 100 printf("%d ", b); 101 update(b, a+b-1, 1, 1, n, 1); 102 } 103 else { 104 scanf("%d %d", &a, &b); 105 update(a, a+b-1, 0, 1, n, 1); 106 } 107 } 108 } 109 return 0; 110 }