最近一直在看胡浩的【完全版】线段树,这个题目是在他的blog介绍的
文字没有参考别人的成分
题目大意:Hotel有N(1 ≤ N ≤ 50,000)间rooms,并且所有的rooms都是连续排列在同一边,groups需要check in 房间,要求房间的编号为连续的r..r+Di-1并且r是最小的;visitors同样可能check out,并且他们每次check out都是编号为Xi ..Xi +Di-1 (1 ≤ Xi ≤ N-Di+1)的房间,题目的输入有两种样式:
要求对于每次request,输出为groups分配数目为a的房间中编号最小的房间编号
思路:利用线段树建立模型,维护最大连续区间长度,其中区间长度就是对应的房间数目,并且对应区间中最左边的断点就是answer,同时因为需要求出连续区间的最大长度,因此每次PushUp时都将左右区间合并,lsum维护左区间的最大长度,rsum维护右区间的最大长度,sum维护区间1…N中的最大连续区间长度,cover标志对应区间是否为空(没有住客)
具体实现过程:
BuildTree:建立一颗线段树,其中lsum,rsum,sum初始化为对应区间的长度
Query :询问是否有长度为a的连续区间,如果有,返回对应区间的最左边的断点
UpData :更新线段树的信息
PushUp :将左右子区间合并
PushDown :标志向下传,延迟标志,简单来说就是先标志,然后等到下次询问或者更新时再去更新线段树
代码:
1 #include <stdio.h> 2 3 #define lson l, m, rt<<1 4 #define rson m+1, r, rt<<1|1 5 6 const int maxn = 50000; 7 8 int n, mNum, op, a, b; 9 int sum[maxn*3], lsum[maxn*3], rsum[maxn*3], cover[maxn*3]; 10 11 void BuildTree(int l, int r, int rt) 12 { 13 cover[rt] = -1; 14 lsum[rt] = rsum[rt] = sum[rt] = r-l+1; 15 if (l == r) 16 return ; 17 18 int m = (l+r)>>1; 19 BuildTree(lson); 20 BuildTree(rson); 21 }/* BuildTree */ 22 23 void PushDown(int rt, int k) 24 { 25 if (cover[rt] != -1) 26 { /* Lazy Tag */ 27 cover[rt<<1] = cover[rt<<1|1] = cover[rt]; 28 lsum[rt<<1] = rsum[rt<<1] = sum[rt<<1] = cover[rt] ? 0:(k-(k>>1)); 29 lsum[rt<<1|1] = rsum[rt<<1|1] = sum[rt<<1|1] = cover[rt] ? 0:(k>>1); 30 cover[rt] = -1; 31 } 32 }/* PushDown */ 33 34 int query(int w, int l, int r, int rt) 35 { 36 if (l == r) 37 return 1; 38 39 PushDown(rt, r-l+1); /* Push Down */ 40 41 int m = (l+r)>>1; 42 if (sum[rt<<1] >= w) /* 左连续区间长度 */ 43 return query(w, lson); 44 else if (rsum[rt<<1]+lsum[rt<<1|1] >= w) /* 左区间后半部分与右区间左半部分长度 */ 45 return m-rsum[rt<<1]+1; 46 else /* 右连续区间长度 */ 47 return query(w, rson); 48 }/* query */ 49 50 int Max(int x, int y) 51 { 52 return (x>y ? x:y); 53 }/* Max */ 54 55 void PushUp(int rt, int k) 56 { 57 lsum[rt] = lsum[rt<<1]; /* 左区间的左半部分 */ 58 rsum[rt] = rsum[rt<<1|1]; /* 右区间的右半部分 */ 59 60 if (lsum[rt] == k-(k>>1)) 61 lsum[rt] += lsum[rt<<1|1]; 62 if (rsum[rt] == k>>1) 63 rsum[rt] += rsum[rt<<1]; 64 65 sum[rt] = Max(rsum[rt<<1]+lsum[rt<<1|1], Max(sum[rt<<1], sum[rt<<1|1])); 66 }/* PushUp */ 67 68 void UpData(int L, int R, int c, int l, int r, int rt) 69 { 70 if (L<=l && r<=R) 71 { 72 lsum[rt] = rsum[rt] = sum[rt] = c ? 0 : r-l+1; 73 cover[rt] = c; 74 75 return ; 76 }/* End of If */ 77 78 PushDown(rt, r-l+1); /* Push Down */ 79 80 int m = (l+r)>>1; 81 if (L <= m) 82 UpData(L, R, c, lson); 83 if (R > m) 84 UpData(L, R, c, rson); 85 86 PushUp(rt, r-l+1); /* Push Up */ 87 }/* Updata */ 88 89 int main() 90 { 91 scanf("%d %d", &n, &mNum); 92 93 BuildTree(1, n, 1); /* BuildTree */ 94 for (int i=1; i<=mNum; ++i) 95 { 96 scanf("%d", &op); 97 if (op == 1) 98 { // Request 99 scanf("%d", &a); 100 if (sum[1] < a) 101 printf("0\n"); /* No result */ 102 else 103 { 104 int pos = query(a, 1, n, 1); 105 printf("%d\n", pos); 106 UpData(pos, pos+a-1, 1, 1, n, 1); /* UpData the interval */ 107 } 108 }/* End of If */ 109 else 110 { 111 scanf("%d %d", &a, &b); 112 UpData(a, a+b-1, 0, 1, n, 1); /* UpData the interval */ 113 } 114 }/* End of For */ 115 116 return 0; 117 }