线段树专题训练
模块一:
线段树单点更新,区间最值。
http://acm.hdu.edu.cn/showproblem.php?pid=1166
线段树功能:update:单点更新,query:区间求和。
http://acm.hdu.edu.cn/showproblem.php?pid=1754
线段树功能:update:单点更新,query:区间最值。
PushUp(int rt) : 把当前节点的信息更新到父亲节点
PushDown(int rt) : 把父亲节点的信息更新到儿子节点。
1 /************************************************************************* 2 > File Name: hdu1754.cpp 3 > Author: syhjh 4 > Created Time: 2014年03月20日 星期四 21时52分56秒 5 ************************************************************************/ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 #include <algorithm> 10 using namespace std; 11 12 #define lson rt << 1 13 #define rson rt << 1 | 1 14 const int MAXN = (200000 + 200); 15 template < class T > inline T getMax(const T &a, const T &b) 16 { 17 return a > b ? a : b; 18 } 19 20 int sum[MAXN << 2]; 21 int N, M; 22 23 void PushUp(int rt) 24 { 25 sum[rt] = getMax(sum[lson], sum[rson]); 26 } 27 28 void Build(int L, int R, int rt) 29 { 30 if (L == R) { 31 scanf("%d", &sum[rt]); 32 return; 33 } 34 int M = (L + R) >> 1; 35 Build(L, M, lson); 36 Build(M + 1, R, rson); 37 PushUp(rt); 38 } 39 40 void Update(int L, int R, int rt, int p, int x) 41 { 42 if (L == R) { 43 sum[rt] = x; 44 return; 45 } 46 int M = (L + R) >> 1; 47 if (p <= M) { 48 Update(L, M, lson, p, x); 49 } else 50 Update(M + 1, R, rson, p, x); 51 PushUp(rt); 52 } 53 54 int Query(int L, int R, int rt, int l, int r) 55 { 56 if (l <= L && R <= r) { 57 return sum[rt]; 58 } 59 int M = (L + R) >> 1; 60 int res = 0; 61 if (l <= M) res = getMax(res, Query(L, M, lson, l, r)); 62 if (r > M) res = getMax(res, Query(M + 1, R, rson, l, r)); 63 return res; 64 } 65 66 int main() 67 { 68 while (cin >> N >> M) { 69 Build(1, N, 1); 70 while (M--) { 71 char str[11]; 72 int x, y; 73 scanf("%s", str); 74 if (str[0] == 'U') { 75 scanf("%d %d", &x, &y); 76 Update(1, N, 1, x, y); 77 } else if (str[0] == 'Q') { 78 scanf("%d %d", &x, &y); 79 int ans = Query(1, N, 1, x, y); 80 printf("%d\n", ans); 81 } 82 } 83 } 84 return 0; 85 }
http://acm.hdu.edu.cn/showproblem.php?pid=1394
可以先求开始序列的逆序数,一开始记录每个叶子节点的值为0,然后对于每个数,插入之后更新一下,对于当前的x[i],需要插叙[x[i], n - 1]之间的数已经出现了多少个。求出一开始的逆序数之后,就可以通过递推关系式以此找出后面的逆序数对。
1 #define _CRT_SECURE_NO_WARNINGS 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 #define lson rt << 1 9 #define rson rt << 1 | 1 10 const int MAXN = (5000 + 50); 11 template < class T > inline T getMIN(const T &a, const T &b) 12 { 13 return a < b ? a : b; 14 } 15 int sum[MAXN << 2]; 16 17 void PushUp(int rt) 18 { 19 sum[rt] = sum[lson] + sum[rson]; 20 } 21 22 void Build(int L, int R, int rt) 23 { 24 sum[rt] = 0; 25 if (L == R) return; 26 int M = (L + R) >> 1; 27 Build(L, M, lson); 28 Build(M + 1, R, rson); 29 } 30 31 void Update(int L, int R, int rt, int p) 32 { 33 if (L == R) { 34 sum[rt]++; 35 return; 36 } 37 int M = (L + R) >> 1; 38 if (p <= M) Update(L, M, lson, p); 39 else Update(M + 1, R, rson, p); 40 PushUp(rt); 41 } 42 43 int Query(int L, int R, int rt, int l, int r) 44 { 45 if (l <= L && R <= r) { 46 return sum[rt]; 47 } 48 int M = (L + R) >> 1; 49 int ret = 0; 50 if (l <= M) ret += Query(L, M, lson, l, r); 51 if (r > M) ret += Query(M + 1, R, rson, l, r); 52 return ret; 53 } 54 55 int n, num[MAXN]; 56 int main() 57 { 58 while (~scanf("%d", &n)) { 59 for (int i = 0; i < n; i++) { 60 scanf("%d", &num[i]); 61 } 62 Build(0, n - 1, 1); 63 int sum = 0; 64 for (int i = 0; i < n; i++) { 65 sum += Query(0, n - 1, 1, num[i], n - 1); 66 Update(0, n - 1, 1, num[i]); 67 } 68 int ans = sum; 69 for (int i = 0; i < n; i++) { 70 sum += (n - num[i] - 1) - num[i]; 71 ans = getMIN(ans, sum); 72 } 73 printf("%d\n", ans); 74 } 75 return 0; 76 }
http://acm.hdu.edu.cn/showproblem.php?pid=2795
这题的本质是区间最大值,这是线段树的长处。
叶子节点x表示board的x行还能放的长度,于是对于区间[a, b]就是表示第a行到b行所能放的最大的长度,那么我们可以从根节点开始比较,如果当前长度小于跟节点的值,就往左子树走,否则就往右子树走,达到叶子节点的时候,len[rt] -= x表示在这一行放置了长度为x的广告,于是剩下的长度就要减少了,然后在update就可以了。
1 #define _CRT_SECURE_NO_WARNINGS 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 #define lson rt << 1 9 #define rson rt << 1 | 1 10 const int MAXN = (200000 + 20); 11 int h, w, n; 12 int len[MAXN << 2]; 13 14 template< class T > inline T getMIN(const T &a, const T &b) 15 { 16 return a < b ? a : b; 17 } 18 19 template< class T > inline T getMAX(const T &a, const T &b) 20 { 21 return a > b ? a : b; 22 } 23 24 void PushUp(int rt) 25 { 26 len[rt] = getMAX(len[lson], len[rson]); 27 } 28 29 void Build(int L, int R, int rt) 30 { 31 len[rt] = w; 32 if (L == R) return; 33 int M = (L + R) >> 1; 34 Build(L, M, lson); 35 Build(M + 1, R, rson); 36 } 37 38 int Query(int L, int R, int rt, int x) 39 { 40 if (L == R) { 41 len[rt] -= x; 42 return L; 43 } 44 int M = (L + R) >> 1; 45 int ret = (len[lson] >= x ? Query(L, M, lson, x) : Query(M + 1, R, rson, x)); 46 PushUp(rt); 47 return ret; 48 } 49 50 int main() 51 { 52 int x; 53 while (~scanf("%d %d %d", &h, &w, &n)) { 54 h = getMIN(h, n); 55 Build(1, h, 1); 56 for (int i = 1; i <= n; i++) { 57 scanf("%d", &x); 58 if (x > len[1]) { 59 puts("-1"); 60 continue; 61 } 62 printf("%d\n", Query(1, h, 1, x)); 63 } 64 } 65 return 0; 66 }
http://poj.org/problem?id=2828
采用倒序插入,pos的意义就是找到一个位置,它的前面刚好有pos个空位,用一个empty数组记录区间[l,r]之间有多少个空位,然后进来一个p,比较左右子树的空位数,如果坐标的空位数 >= p,那么说明p应该放在左子树,否则,p应该放右子树,并且p还要减去左子树的空位数,因为右子树的空位数也是从0开始的。
1 #define _CRT_SECURE_NO_WARNINGS 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 #define lson rt << 1 9 #define rson rt << 1 | 1 10 const int MAXN = (200000 + 20); 11 int empty[MAXN << 2]; 12 int n, index, pos[MAXN], id[MAXN], ans[MAXN]; 13 14 void Build(int L, int R, int rt) 15 { 16 empty[rt] = R - L + 1; 17 if (L == R) return; 18 int M = (L + R) >> 1; 19 Build(L, M, lson); 20 Build(M + 1, R, rson); 21 } 22 23 void Update(int L, int R, int rt, int p) 24 { 25 empty[rt]--; 26 if (L == R) { 27 index = L; 28 return; 29 } 30 int M = (L + R) >> 1; 31 if (empty[lson] >= p) Update(L, M, lson, p); 32 else p -= empty[lson], Update(M + 1, R, rson, p); 33 } 34 35 int main() 36 { 37 while (~scanf("%d", &n)) { 38 for (int i = 1; i <= n; i++) { 39 scanf("%d %d", &pos[i], &id[i]); 40 } 41 Build(1, n, 1); 42 for (int i = n; i >= 1; i--) { 43 Update(1, n, 1, pos[i] + 1); 44 ans[index] = id[i]; 45 } 46 for (int i = 1; i <= n; i++) { 47 printf(i == n ? "%d\n" : "%d ", ans[i]); 48 } 49 } 50 return 0; 51 }
http://poj.org/problem?id=2481
对n头牛先按S从小到大排序,在按E从大到小排序,这样每次计算一个,我们可以找比当前的e大的出现的数目,然后更新即可,线段树的查找和更新的复杂度均为n * log(n).
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 #define lson rt << 1 8 #define rson rt << 1 | 1 9 const int MAXN = (100000 + 100); 10 template< typename T > inline T getMAX(const T &a, const T &b) 11 { 12 return a > b ? a : b; 13 } 14 15 struct Node { 16 int s, e, id; 17 } node[MAXN]; 18 19 int cmp(const Node &p, const Node &q) 20 { 21 if (p.s != q.s) { 22 return p.s < q.s; 23 } 24 return p.e > q.e; 25 } 26 27 int N; 28 int sum[MAXN << 2]; 29 30 void PushUp(int rt) 31 { 32 sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; 33 } 34 35 void Build(int L, int R, int rt) 36 { 37 sum[rt] = 0; 38 if (L == R) return; 39 int M = (L + R) >> 1; 40 Build(L, M, lson); 41 Build(M + 1, R, rson); 42 } 43 44 void Update(int L, int R, int rt, int p) 45 { 46 if (L == R) { 47 sum[rt]++; 48 return; 49 } 50 int M = (L + R) >> 1; 51 if (p <= M) Update(L, M, lson, p); 52 else Update(M + 1, R, rson, p); 53 PushUp(rt); 54 } 55 56 int Query(int L, int R, int rt, int l, int r) 57 { 58 if (l <= L && R <= r) { 59 return sum[rt]; 60 } 61 int M = (L + R) >> 1; 62 int ret = 0; 63 if (l <= M) ret += Query(L, M, lson, l, r); 64 if (r > M) ret += Query(M + 1, R, rson, l, r); 65 return ret; 66 } 67 68 69 int ans[MAXN]; 70 int MAX; 71 int main() 72 { 73 while (~scanf("%d", &N) && N) { 74 MAX = 0; 75 for (int i = 0; i < N; i++) { 76 scanf("%d %d", &node[i].s, &node[i].e); 77 MAX = getMAX(MAX, node[i].e); 78 node[i].id = i; 79 } 80 sort(node, node + N, cmp); 81 Build(1, MAX, 1); 82 ans[node[0].id] = 0; 83 Update(1, MAX, 1, node[0].e); 84 for (int i = 1; i < N; i++) { 85 if (node[i].s == node[i - 1].s && node[i].e == node[i - 1].e) { 86 ans[node[i].id] = ans[node[i - 1].id]; 87 } else 88 ans[node[i].id] = Query(1, MAX, 1, node[i].e, MAX); 89 Update(1, MAX, 1, node[i].e); 90 } 91 for (int i = 0; i < N; i++) { 92 if (i == N - 1) printf("%d\n", ans[i]); 93 else printf("%d ", ans[i]); 94 } 95 } 96 return 0; 97 }
http://poj.org/problem?id=2182
len数组代表当前节点的区间还有的空位置,那么我们可以从后往前依次放位置,这样就能确定最后的序列了!
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 #define lson rt << 1 8 #define rson rt << 1 | 1 9 const int MAXN = (8000 + 80); 10 int len[MAXN << 2]; 11 int num[MAXN], ans[MAXN], pos, N; 12 13 void Build(int L, int R, int rt) 14 { 15 len[rt] = R - L + 1; 16 if (L == R) return; 17 int M = (L + R) >> 1; 18 Build(L, M, lson); 19 Build(M + 1, R, rson); 20 } 21 22 void Update(int L, int R, int rt, int p) 23 { 24 len[rt]--; 25 if (L == R) { 26 pos = L; 27 return; 28 } 29 int M = (L + R) >> 1; 30 if (p <= len[lson]) Update(L, M, lson, p); 31 else Update(M + 1, R, rson, p - len[lson]); 32 } 33 34 int main() 35 { 36 while (~scanf("%d", &N)) { 37 num[1] = 0; 38 for (int i = 2; i <= N; i++) { 39 scanf("%d", &num[i]); 40 } 41 Build(1, N, 1); 42 for (int i = N; i >= 1; i--) { 43 Update(1, N, 1, num[i] + 1); 44 ans[i] = pos; 45 } 46 for (int i = 1; i <= N; i++) { 47 printf("%d\n", ans[i]); 48 } 49 } 50 return 0; 51 }
模块二:线段树成段更新。
http://acm.hdu.edu.cn/showproblem.php?pid=1698
col数组要来标记当前区间的值,一开始所有的区间都为0,然后我们更新的时候,如果当前的区间的col不为0,则说明该区间是纯的,此时,我们应该把这个区间的col往左右子树传,同时计算sum的值,由于是纯的,因此当前节点的左子树和当前节点的右子树的sum可以直接求得,然后在把当前的col改为0,表示当前节点覆盖的区间不纯。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 #define lson rt << 1 8 #define rson rt << 1 | 1 9 const int MAXN = (100000 + 100); 10 int N, M; 11 int col[MAXN << 2], sum[MAXN << 2]; 12 13 void PushDown(int rt, int len) 14 { 15 if (col[rt]) { 16 col[lson] = col[rson] = col[rt]; 17 sum[lson] = (len - (len >> 1)) * col[rt]; 18 sum[rson] = (len >> 1) * col[rt]; 19 col[rt] = 0; //不纯洁 20 } 21 } 22 23 void PushUp(int rt) 24 { 25 sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; 26 } 27 28 29 void Build(int L, int R, int rt) 30 { 31 col[rt] = 0; 32 sum[rt] = 1; 33 if (L == R) return; 34 int M = (L + R) >> 1; 35 Build(L, M, lson); 36 Build(M + 1, R, rson); 37 PushUp(rt); 38 } 39 40 void Update(int L, int R, int rt, int l, int r, int color) 41 { 42 if (l <= L && R <= r) { 43 col[rt] = color; 44 sum[rt] = (R - L + 1) * color; 45 return; 46 } 47 PushDown(rt, R - L + 1); 48 int M = (L + R) >> 1; 49 if (l <= M) Update(L, M, lson, l, r, color); 50 if (r > M) Update(M + 1, R, rson, l, r, color); 51 PushUp(rt); 52 } 53 54 int main() 55 { 56 int Cas, t = 1; 57 scanf("%d", &Cas); 58 while (Cas--) { 59 scanf("%d %d", &N, &M); 60 Build(1, N, 1); 61 for (int i = 0; i < M; i++) { 62 int a, b, c; 63 scanf("%d %d %d", &a, &b, &c); 64 Update(1, N, 1, a, b, c); 65 } 66 printf("Case %d: The total value of the hook is %d.\n", t++, sum[1]); 67 } 68 return 0; 69 }
http://poj.org/problem?id=3468
线段树成段更新,采用lazy思想,记录增量,更新的时候只更新到段,等到下次更新或者查询的时候,碰到已经被标记过的,往下顺延就行。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 #define lson rt << 1 8 #define rson rt << 1 | 1 9 typedef long long ll; 10 const int MAXN = (100000 +100); 11 int N, Q; 12 ll sum[MAXN << 2], add[MAXN << 2]; 13 14 void PushUp(int rt) 15 { 16 sum[rt] = sum[lson] + sum[rson]; 17 } 18 19 void PushDown(int rt, int len) 20 { 21 if (add[rt]) { 22 add[lson] += add[rt]; 23 add[rson] += add[rt]; 24 sum[lson] += (len - (len >> 1)) * add[rt]; 25 sum[rson] += (len >> 1) * add[rt]; 26 add[rt] = 0; 27 } 28 } 29 30 void Build(int L, int R, int rt) 31 { 32 add[rt] = 0; 33 if (L == R) { 34 scanf("%lld", &sum[rt]); 35 return; 36 } 37 int M = (L + R) >> 1; 38 Build(L, M, lson); 39 Build(M + 1, R, rson); 40 PushUp(rt); 41 } 42 43 void Update(int L, int R, int rt, int l, int r, int lnc) 44 { 45 if (l <= L && R <= r) { 46 add[rt] += lnc; 47 sum[rt] += (R - L + 1) * lnc; 48 return; 49 } 50 PushDown(rt, R - L + 1); 51 int M = (L + R) >> 1; 52 if (l <= M) Update(L, M, lson, l, r, lnc); 53 if (r > M) Update(M + 1, R, rson, l, r, lnc); 54 PushUp(rt); 55 } 56 57 ll Query(int L, int R, int rt, int l, int r) 58 { 59 if (l <= L && R <= r) { 60 return sum[rt]; 61 } 62 PushDown(rt, R - L + 1); 63 int M = (L + R) >> 1; 64 ll ret = 0; 65 if (l <= M) ret += Query(L, M, lson, l, r); 66 if (r > M) ret += Query(M + 1, R, rson, l, r); 67 return ret; 68 } 69 70 int main() 71 { 72 scanf("%d %d", &N, &Q); 73 Build(1, N, 1); 74 while (Q--) { 75 char str[2]; 76 int a, b, c; 77 scanf("%s", str); 78 if (str[0] == 'Q') { 79 scanf("%d %d", &a, &b); 80 printf("%lld\n", Query(1, N, 1, a, b)); 81 } else if (str[0] == 'C') { 82 scanf("%d %d %d", &a, &b, &c); 83 Update(1, N, 1, a, b, c); 84 } 85 } 86 return 0; 87 }
http://acm.cug.edu.cn/JudgeOnline/problem.php?id=1435
线段树成段更新,区间最值。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 #define lson rt << 1 8 #define rson rt << 1 | 1 9 typedef long long ll; 10 const int MAXN = (100000 + 100); 11 template < typename T > inline T getMIN(const T &a, const T &b) 12 { 13 return a < b ? a : b; 14 } 15 16 int N, M; 17 ll MIN[MAXN << 2], add[MAXN << 2]; 18 19 void PushDown(int rt) 20 { 21 if (add[rt]) { 22 add[lson] += add[rt]; 23 add[rson] += add[rt]; 24 MIN[lson] += add[rt]; 25 MIN[rson] += add[rt]; 26 add[rt] = 0; 27 } 28 } 29 30 void PushUp(int rt) 31 { 32 MIN[rt] = getMIN(MIN[lson], MIN[rson]); 33 } 34 35 void Build(int L, int R, int rt) 36 { 37 add[rt] = 0; 38 if (L == R) { 39 scanf("%lld", &MIN[rt]); 40 return; 41 } 42 int M = (L + R) >> 1; 43 Build(L, M, lson); 44 Build(M + 1, R, rson); 45 PushUp(rt); 46 } 47 48 void Update(int L, int R, int rt, int l, int r, int lnc) 49 { 50 if (l <= L && R <= r) { 51 add[rt] += lnc; 52 MIN[rt] += lnc; 53 return; 54 } 55 PushDown(rt); 56 int M = (L + R) >> 1; 57 if (l <= M) Update(L, M, lson, l, r, lnc); 58 if (r > M) Update(M + 1, R, rson, l, r, lnc); 59 PushUp(rt); 60 } 61 62 ll Query(int L, int R, int rt, int l, int r) 63 { 64 if (l <= L && R <= r) { 65 return MIN[rt]; 66 } 67 PushDown(rt); 68 int M = (L + R) >> 1; 69 ll ans = 1LL << 60; 70 if (l <= M) ans = getMIN(ans, Query(L, M, lson, l, r)); 71 if (r > M) ans = getMIN(ans, Query(M + 1, R, rson, l, r)); 72 return ans; 73 } 74 75 int Judge(char *str) 76 { 77 int len = strlen(str), cnt = 0; 78 for (int i = 0; i < len; ) { 79 if (str[i] == ' ') { 80 cnt++; 81 while (i < len && str[i] == ' ') i++; 82 } else 83 i++; 84 } 85 return cnt; 86 } 87 88 int main() 89 { 90 while (~scanf("%d %d", &N, &M)) { 91 Build(0, N - 1, 1); 92 getchar(); 93 while (M--) { 94 char str[22]; 95 int a, b, c; 96 gets(str); 97 if (Judge(str) == 1) { 98 sscanf(str, "%d %d", &a, &b); 99 if (a <= b) { 100 printf("%lld\n", Query(0, N - 1, 1, a, b)); 101 } else 102 printf("%lld\n", getMIN(Query(0, N - 1, 1, a, N - 1), Query(0, N - 1, 1, 0, b))); 103 } else if (Judge(str) == 2) { 104 sscanf(str, "%d %d %d", &a, &b, &c); 105 if (a <= b) { 106 Update(0, N - 1, 1, a, b, c); 107 } else { 108 Update(0, N - 1, 1, 0, b, c); 109 Update(0, N - 1, 1, a, N - 1, c); 110 } 111 } 112 } 113 } 114 return 0; 115 }
http://poj.org/problem?id=2528
线段树 + 离散化。
http://www.notonlysuccess.com/index.php/segment-tree-complete/大牛的博客讲得很清楚!
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 #define lson rt << 1 8 #define rson rt << 1 | 1 9 const int MAXN = (100000 + 100); 10 struct Node { 11 int l, r; 12 } node[MAXN]; 13 14 bool Hash[MAXN]; 15 int X[MAXN << 2]; 16 int col[MAXN << 4]; 17 int cnt, n, m; 18 19 void PushDown(int rt) 20 { 21 if (col[rt] != -1) { 22 col[lson] = col[rson] = col[rt]; 23 col[rt] = -1; 24 } 25 } 26 27 void Update(int L, int R, int rt, int l, int r, int color) 28 { 29 if (l <= L && R <= r) { 30 col[rt] = color; 31 return; 32 } 33 PushDown(rt); 34 int M = (L + R) >> 1; 35 if (l <= M) Update(L, M, lson, l, r, color); 36 if (r > M) Update(M + 1, R, rson, l, r, color); 37 } 38 39 void Query(int L, int R, int rt) 40 { 41 if (col[rt] != -1) { 42 if (!Hash[col[rt]]) cnt++; 43 Hash[col[rt]] = true; 44 return; 45 } 46 if (L == R) return; 47 int M = (L + R) >> 1; 48 Query(L, M, lson); 49 Query(M + 1, R, rson); 50 } 51 52 int Binary_Search(int low, int high, int number) 53 { 54 while (low <= high) { 55 int mid = (low + high) >> 1; 56 if (X[mid] == number) return mid; 57 else if (X[mid] < number) low = mid +1; 58 else high = mid - 1; 59 } 60 return low; 61 } 62 63 int main() 64 { 65 int Cas; 66 scanf("%d", &Cas); 67 while (Cas--) { 68 scanf("%d", &m); 69 cnt = n = 0; 70 for (int i = 0; i < m; i++) { 71 scanf("%d %d", &node[i].l, &node[i].r); 72 X[n++] = node[i].l; 73 X[n++] = node[i].r; 74 } 75 sort(X, X + n); 76 n = unique(X, X + n) - X; 77 for (int i = n - 1; i > 0; i--) { 78 if (X[i] != X[i - 1] + 1) X[n++] = X[i - 1] + 1; 79 } 80 sort(X, X + n); 81 memset(col, -1, sizeof(col)); 82 for (int i = 0; i < m; i++) { 83 int l = Binary_Search(0, n - 1, node[i].l); 84 int r = Binary_Search(0, n - 1, node[i].r); 85 Update(0, n - 1, 1, l, r, i); 86 } 87 memset(Hash, false, sizeof(Hash)); 88 Query(0, n - 1, 1); 89 printf("%d\n", cnt); 90 } 91 return 0; 92 }
http://poj.org/problem?id=3225
线段树:区间异或,成段更新。
集合操作:
U: 把区间[l, r]覆盖成1
I: 把区间(-oo, l)和(r, +oo)覆盖成0
D:把区间(l, r) 覆盖成0
C: 把区间(-oo, l)和(r, +oo)覆盖成0,并且把[l, r]区间0、1互换
S: 把区间[l, r]0、1互换
0、1互换的过程实际上也就是异或的过程;
成段更新操作与之前的类似,不同的是异或的操作。
显然,当一个区间被覆盖后,不管之前有没有异或标记都没有意义了,因此应该把异或标记清0;
当一个节点得到异或标记的时候,应该先判断该节点的覆盖标记,如果该节点的覆盖标记为0/1(标记为-1,表示不是完全包含或者完全不包含),直接改变覆盖标记,否则改变异或标记。
至于如果来区别开闭区间,我们可以将区间扩大两倍,即:
左闭:x - > 2 * x
左开: x - > 2 * x + 1
右闭:y - > 2 * y;
右开: y - > 2 * y - 1
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 #define lson rt << 1 8 #define rson rt << 1 | 1 9 const int MAXN = (65537 << 1); 10 bool mark[MAXN]; 11 int cover[MAXN << 2]; 12 int XOR[MAXN << 2]; 13 14 void FXOR(int rt) 15 { 16 if (cover[rt] != -1) { 17 cover[rt] ^= 1; 18 } else 19 XOR[rt] ^= 1; 20 } 21 22 void PushDown(int rt) 23 { 24 if (cover[rt] != -1) { 25 cover[lson] = cover[rson] = cover[rt]; 26 XOR[lson] = XOR[rson] = 0; 27 cover[rt] = -1; 28 } 29 if (XOR[rt]) { 30 FXOR(lson); 31 FXOR(rson); 32 XOR[rt] = 0; 33 } 34 } 35 36 void Update(int L, int R, int rt, int l, int r, char ch) 37 { 38 if (l <= L && R <= r) { 39 if (ch == 'U') { 40 cover[rt] = 1; 41 XOR[rt] = 0; 42 } else if (ch == 'D') { 43 cover[rt] = 0; 44 XOR[rt] = 0; 45 } else if (ch == 'C' || ch == 'S') { 46 FXOR(rt); 47 } 48 return; 49 } 50 PushDown(rt); 51 int M = (L + R) >> 1; 52 if (l <= M) Update(L, M, lson, l, r, ch); 53 else if (ch == 'I' || ch == 'C') { 54 XOR[lson] = cover[lson] = 0; 55 } 56 if (r > M) Update(M + 1, R, rson, l, r, ch); 57 else if (ch == 'I' || ch == 'C') { 58 XOR[rson] = cover[rson] = 0; 59 } 60 } 61 62 void Query(int L, int R, int rt) 63 { 64 if (cover[rt] != -1) { 65 if (cover[rt] == 1) { 66 for (int i = L; i <= R; i++) { 67 mark[i] = true; 68 } 69 } 70 return; 71 } 72 PushDown(rt); 73 int M = (L + R) >> 1; 74 Query(L, M, lson); 75 Query(M + 1, R, rson); 76 } 77 78 int main() 79 { 80 cover[1] = XOR[1] = 0; 81 char ch, op1, op2; 82 int a, b; 83 memset(mark, false, sizeof(mark)); 84 while (~scanf("%c %c%d,%d%c\n", &ch, &op1, &a, &b, &op2)) { 85 a <<= 1; 86 b <<= 1; 87 if (op1 == '(') { 88 a++; 89 } 90 if (op2 == ')') { 91 b--; 92 } 93 if (a > b) { 94 if (ch == 'I' || ch == 'C') { 95 cover[1] = XOR[1] = 0; 96 } 97 } else 98 Update(0, MAXN, 1, a, b, ch); 99 } 100 Query(0, MAXN, 1); 101 bool flag = false; 102 int st = -1, ed; 103 for (int i = 0; i <= MAXN; i++) { 104 if (mark[i]) { 105 if (st == -1) st = i; 106 ed = i; 107 } else { 108 if (st != -1) { 109 if (flag) printf(" "); 110 flag = true; 111 printf("%c%d,%d%c", st & 1 ? '(' : '[', st >> 1, (ed + 1) >> 1, ed & 1 ? ')' : ']'); 112 st = -1; 113 } 114 } 115 } 116 if (!flag) printf("empty set"); 117 puts(""); 118 return 0; 119 }