hdu 2871 Memory Control
http://acm.hdu.edu.cn/showproblem.php?pid=2871
这是要用线段树的一道模拟题,题意相当简单,就是模拟内存分配的操作。题目用到线段树【单点更新,单点查询,区间更新,查找区间】的功能。
New:寻找是否有大于指定长度的区间,并将区间染色,标记起始位置。
Free:查询单点值,如果已被占用,则删除该区间。
Get:查找第x个区间,并返回起始位置。
Reset:将区间清空。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <algorithm> 5 #include <cassert> 6 7 using namespace std; 8 9 #define lson l, m, rt << 1 10 #define rson m + 1, r, rt << 1 | 1 11 12 typedef vector<int> vi; 13 const int maxn = 50005; 14 15 vi start, end; 16 int cnt[maxn << 2], mark[maxn << 2], late[maxn << 2], left[maxn << 2], right[maxn << 2], mx[maxn << 2]; 17 18 /*****以下是统计端点位置与个数的线段树*****/ 19 void build(int l, int r, int rt){ 20 cnt[rt] = 0; 21 if (l == r){ 22 return ; 23 } 24 int m = (l + r) >> 1; 25 26 build(lson); 27 build(rson); 28 } 29 30 void up1(int rt){ 31 cnt[rt] = cnt[rt << 1] + cnt[rt << 1 | 1]; 32 } 33 34 void add1(int key, int p, int l, int r, int rt){ 35 if (l == r){ 36 //assert(l == p); 37 cnt[rt] += key; 38 return ; 39 } 40 int m = (l + r) >> 1; 41 42 if (p <= m) add1(key, p, lson); 43 else add1(key, p, rson); 44 up1(rt); 45 } 46 47 int find1(int k, int l, int r, int rt){ 48 if (l == r){ 49 return l; 50 } 51 int m = (l + r) >> 1; 52 53 //printf("%d %d %d cnt %d\n", k, l, r, cnt[rt << 1]); 54 if (cnt[rt << 1] >= k) return find1(k, lson); 55 else return find1(k - cnt[rt << 1], rson); 56 } 57 /******************************************/ 58 59 60 /*******以下是标记区间占用情况的线段树*******/ 61 void up2(int rt, int len){ 62 int l = rt << 1; 63 int r = rt << 1 | 1; 64 65 mx[rt] = max(max(mx[l], mx[r]), left[r] + right[l]); 66 if (left[l] == len - (len >> 1)) left[rt] = left[l] + left[r]; 67 else left[rt] = left[l]; 68 if (right[r] == (len >> 1)) right[rt] = right[r] + right[l]; 69 else right[rt] = right[r]; 70 } 71 72 void down2(int rt, int len){ 73 if (late[rt] != -2){ 74 int l = rt << 1; 75 int r = rt << 1 | 1; 76 77 mark[l] = late[l] = late[rt]; 78 mark[r] = late[r] = late[rt]; 79 if (~late[rt]){ 80 mx[l] = left[l] = right[l] = 0; 81 mx[r] = left[r] = right[r] = 0; 82 } 83 else{ 84 int m = len >> 1; 85 86 mx[l] = left[l] = right[l] = len - m; 87 mx[r] = left[r] = right[r] = m; 88 } 89 late[rt] = -2; 90 } 91 } 92 93 void update2(int k, int L, int R, int l, int r, int rt){ 94 if (L <= l && r <= R){ 95 late[rt] = mark[rt] = k; 96 if (~k){ 97 mx[rt] = left[rt] = right[rt] = 0; 98 } 99 else{ 100 mx[rt] = left[rt] = right[rt] = r - l + 1; 101 } 102 return ; 103 } 104 int m = (l + r) >> 1; 105 106 down2(rt, r - l + 1); 107 if (L <= m) update2(k, L, R, lson); 108 if (m < R) update2(k, L, R, rson); 109 up2(rt, r - l + 1); 110 //printf("%d %d %d %d %d\n", l, r, rt, mx[rt], mx[5]); 111 } 112 113 int find2(int len, int l, int r, int rt){ 114 int m = (l + r) >> 1; 115 int tl = rt << 1, tr = rt << 1 | 1; 116 117 down2(rt, r - l + 1); 118 if (len == r - l + 1) return l; 119 if (mx[tl] >= len){ 120 return find2(len, lson); 121 } 122 else if (right[tl] + left[tr] >= len){ 123 return m - right[tl] + 1; 124 } 125 else{ 126 return find2(len, rson); 127 } 128 } 129 130 int query(int x, int l, int r, int rt){ 131 if (l == r){ 132 //assert(x == l); 133 return mark[rt]; 134 } 135 int m = (l + r) >> 1; 136 137 down2(rt, r - l + 1); 138 if (x <= m) return query(x, lson); 139 else return query(x, rson); 140 } 141 /******************************************/ 142 143 void deal(int n, int m){ 144 char buf[10]; 145 int k; 146 147 start.clear(); 148 end.clear(); 149 150 update2(-1, 1, n, 1, n, 1); 151 build(1, n, 1); 152 //puts("Built!"); 153 while (m--){ 154 scanf("%s", buf); 155 if (!strcmp(buf, "Reset")){ 156 update2(-1, 1, n, 1, n, 1); // 重置区间 157 while (cnt[1]){ 158 int t = find1(1, 1, n, 1); 159 add1(-1, t, 1, n, 1); //清空计数器 160 } 161 puts("Reset Now"); 162 } 163 else if (!strcmp(buf, "New")){ 164 scanf("%d", &k); 165 if (mx[1] < k){ 166 puts("Reject New"); 167 continue; 168 } 169 170 int s = find2(k, 1, n, 1); // 查找满足要求的区间的起点 171 int t = start.size(); 172 173 add1(1, s, 1, n, 1); // 起点位置的计数器加一 174 //printf("ss %d %d\n", s, s + k - 1); 175 update2(t, s, s + k - 1, 1, n, 1); //更新区间 176 //printf("mx %d\n", mx[1]); 177 start.push_back(s); 178 end.push_back(s + k - 1); 179 printf("New at %d\n", s); 180 } 181 else if (!strcmp(buf, "Free")){ 182 scanf("%d", &k); 183 184 int t = query(k, 1, n, 1); // 找到位置所属区间的标号 185 //printf("tt %d\n", t); 186 if (~t){ 187 //printf("s %d t %d\n", start[t], end[t]); 188 update2(-1, start[t], end[t], 1, n, 1); // 删除区间 189 add1(-1, start[t], 1, n, 1); // 起始位置的计数器减一 190 printf("Free from %d to %d\n", start[t], end[t]); 191 } 192 else{ 193 puts("Reject Free"); 194 } 195 } 196 else if (!strcmp(buf, "Get")){ 197 scanf("%d", &k); 198 if (cnt[1] < k){ 199 puts("Reject Get"); 200 continue; 201 } 202 203 printf("Get at %d\n", find1(k, 1, n, 1)); // 返回第k个区间的位置 204 } 205 } 206 puts(""); 207 } 208 209 int main(){ 210 int n, m; 211 212 //freopen("in", "r", stdin); 213 214 while (~scanf("%d%d", &n, &m)){ 215 deal(n, m); 216 } 217 218 return 0; 219 }
——written by Lyon