POJ 2528 线段树 成段更新+【离散化】 贴海报.cpp
题意:
给出了n份海报的贴在board上的起始位置和结束位置
问最后可以看到多少份海报
输入:
n表示有n份海报
接下来n行 每行 a b 表示海报占据了a~b的位置..
思路:
线段树成段更新
用树的结点value表示控制范围内的海报编号..
因为不用更新到底+查询到每一个叶子节点..所以提高了查询和更新效率..
其中因为海报长度给的很大..
所以可以使用离散化来减少空间的消耗以及查询和更新时的递归次数..
Tips:
因为给出的a b 表示的是在a~b内贴了海报..
所以a b给的是值..但是表示的是一段范围..
如果用正常的离散化..就可能出现
最底下一层贴了一张海报AA..
然后上面贴了两张相邻的海报BB 和 CC
BB.r < CC.l
但是离散化后因为BB和CC是相邻的..所以BB.r = CC.l
这样~本来两张海报之间是有空隙的..可以透过空隙看到AA
结果离散化之后就覆盖了那个空隙..
解决方法就是当发现相隔的两个海报之间的距离>1就在中间加一个数..
离散化的处理方式很有趣吖~~^^
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 for(i = 0; i < n; ++i) { 2 scanf("%d %d", &l, &r); 3 if(vis[l] == 0){//如果没有访问过这个点.. 4 vis[l] = 1; 5 s[tot++] = l;//就把这个点加到离散化的数组里.. 6 } 7 if(vis[r] == 0) { 8 s[tot++] = r; 9 vis[r] = 1; 10 } 11 node[i].l = l, node[i].r = r; 12 } 13 14 sort(s, s+tot); 15 16 for(i = tot-1; i > 0; --i) {//在相邻的海报间增加一个点 17 if(s[i] - s[i-1] > 1) 18 s[tot++] = s[i-1]+1; 19 } 20 sort(s, s+tot); 21 22 for(i = 0; i < n; ++i) {//s数组的下标就是离散化后的值.. 23 l = solve(node[i].l, tot, s); 24 r = solve(node[i].r, tot, s); 25 modify(l, r, i, 0, tot, 1); 26 } 27 28 29 int solve(int key, int tot, int *arr) 30 { 31 int mid; 32 int l = 0, r = tot-1; 33 while(l <= r) { 34 mid = (l+r)>>1; 35 if(arr[mid] == key) return mid; 36 if(arr[mid] > key) r = mid-1; 37 else l = mid+1; 38 } 39 }
还有问题就是if(vis[r] == 0) 有时候 r 会很大..这样写就错了~
所以可以不管有没有增加过这个点都先放入 s 数组里~
然后再去重..
Code:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int MAXN = 40010; 7 int lazy[MAXN<<2]; 8 int arr[MAXN]; 9 int vis[10000010]; 10 int s[MAXN]; 11 int cnt; 12 13 struct Node 14 { 15 int r; 16 int l; 17 }node[MAXN]; 18 19 void pushDown(int rt) 20 { 21 if(lazy[rt] != -1) { 22 lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt]; 23 lazy[rt] = -1; 24 } 25 } 26 27 void modify(int l, int r, int x, int L, int R, int rt) 28 { 29 if(l <= L && r >= R) { 30 lazy[rt] = x; 31 return; 32 } 33 pushDown(rt); 34 int mid = (L+R) >> 1; 35 if(l <= mid) modify(l, r, x, L, mid, rt<<1); 36 if(mid < r) modify(l, r, x, mid+1, R, rt<<1|1); 37 } 38 39 int solve(int key, int tot, int *arr) 40 { 41 int mid; 42 int l = 0, r = tot-1; 43 while(l <= r) { 44 mid = (l+r)>>1; 45 if(arr[mid] == key) return mid; 46 if(arr[mid] > key) r = mid-1; 47 else l = mid+1; 48 } 49 } 50 51 void query(int l, int r, int rt) 52 { 53 if(lazy[rt] != -1) { 54 if(vis[lazy[rt]] == 0) 55 cnt++; 56 vis[lazy[rt]] = 1; 57 return; 58 } 59 if(l == r) return; 60 int mid = (l+r)>>1; 61 query(l, mid, rt<<1); 62 query(mid+1, r, rt<<1|1); 63 } 64 65 int main() 66 { 67 int i, j, k; 68 int n, T; 69 int tot, l, r; 70 while(scanf("%d", &T) != EOF) 71 while(T--) 72 { 73 memset(vis, 0, sizeof(vis)); 74 memset(lazy, 0xff, sizeof(lazy)); 75 tot = cnt = 0; 76 77 scanf("%d", &n); 78 for(i = 0; i < n; ++i) { 79 scanf("%d %d", &l, &r); 80 if(vis[l] == 0){ 81 vis[l] = 1; 82 s[tot++] = l; 83 } 84 if(vis[r] == 0) { 85 s[tot++] = r; 86 vis[r] = 1; 87 } 88 node[i].l = l, node[i].r = r; 89 } 90 91 sort(s, s+tot); 92 93 for(i = tot-1; i > 0; --i) { 94 if(s[i] - s[i-1] > 1) 95 s[tot++] = s[i-1]+1; 96 } 97 sort(s, s+tot); 98 99 for(i = 0; i < n; ++i) { 100 l = solve(node[i].l, tot, s); 101 r = solve(node[i].r, tot, s); 102 modify(l, r, i, 0, tot, 1); 103 } 104 memset(vis, 0, sizeof(vis)); 105 query(0, tot, 1); 106 printf("%d\n", cnt); 107 } 108 return 0; 109 }