最近一直在看胡浩的【完全版】線段樹,這個題目是在他的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)的房間,題目的輸入有兩種樣式:
- 1 a : groups需要check in a間編號連續的房間
- 2 a b : visitors check out 房間,其中房間編號是 a…a+b-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 }