[POJ3667]Hotel(线段树,区间合并)

题目链接: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 }
原文地址:https://www.cnblogs.com/kirai/p/5947305.html