题目链接:
http://poj.org/problem?id=2528
题意:
一个区间贴海报,然后问你在最后,能看见多少个海报
题解:
用每个离散化之后的编号, 区分不同海报, 每次更新都是覆盖前一个值的,最后统计一下有多少不同的v就好了
稍微了解了离散化的姿势:
http://www.cnblogs.com/gongxijun/p/4020322.html
通俗点说,离散化就是压缩区间,使原有的长区间映射到新的短区间,但是区间压缩前后的覆盖关系不变。举个例子:
有一条1到10的数轴(长度为9),给定4个区间[2,4] [3,6] [8,10] [6,9],覆盖关系就是后者覆盖前者,每个区间染色依次为 1 2 3 4。
现在我们抽取这4个区间的8个端点,2 4 3 6 8 10 6 9
然后删除相同的端点,这里相同的端点为6,则剩下2 4 3 6 8 10 9
对其升序排序,得2 3 4 6 8 9 10
然后建立映射
2 3 4 6 8 9 10
↓ ↓ ↓ ↓ ↓ ↓ ↓
1 2 3 4 5 6 7
那么新的4个区间为 [1,3] [2,4] [5,7] [4,6],覆盖关系没有被改变。新数轴为1到7,即原数轴的长度从9压缩到6,显然构造[1,7]的线段树比构造[1,10]的线段树更省空间,搜索也更快,但是求解的结果却是一致的。
离散化时有一点必须要注意的,就是必须先剔除相同端点后再排序,这样可以减少参与排序元素的个数,节省时间。
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <map> 6 #include <algorithm> 7 using namespace std; 8 typedef long long ll; 9 #define MS(a) memset(a,0,sizeof(a)) 10 #define MP make_pair 11 #define PB push_back 12 const int INF = 0x3f3f3f3f; 13 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; 14 inline ll read(){ 15 ll x=0,f=1;char ch=getchar(); 16 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 17 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 ////////////////////////////////////////////////////////////////////////// 21 const int maxn = 1e5+10; 22 23 vector<int> p; 24 map<int,int> H; 25 int flag[maxn]; 26 struct node{ 27 int l,r,v; // l,r 表示这个节点管辖的范围, v表示海报离散化之后的编号 28 void update(int val){ 29 v = val; // 这段区间被后面的海报覆盖了 30 } 31 }tree[maxn<<2]; 32 struct qu{ 33 int x,y; 34 }q[maxn]; 35 36 void pushdown(int rt){ 37 int lazy = tree[rt].v; 38 if(lazy){ 39 tree[rt<<1].update(lazy); 40 tree[rt<<1|1].update(lazy); 41 tree[rt].v = 0; // 传递到孩子了 没有值了 42 } 43 } 44 45 void build(int rt,int l,int r){ 46 tree[rt].l = l, tree[rt].r = r; 47 tree[rt].v = 0; 48 if(l == r) 49 return ; 50 int mid = (l+r)/2; 51 build(rt<<1,l,mid); 52 build(rt<<1|1,mid+1,r); 53 } 54 55 void update(int l,int r,int rt,int va){ 56 int L = tree[rt].l, R = tree[rt].r; 57 if(l<=L && R<=r) 58 tree[rt].update(va); //在rt这个范围是一张海报 59 else{ 60 pushdown(rt); 61 int mid = (L+R)/2; 62 if(l<=mid) update(l,r,rt<<1,va); 63 if(r>mid) update(l,r,rt<<1|1,va); 64 } 65 } 66 67 void query(int rt,int l,int r){ 68 int L = tree[rt].l, R = tree[rt].r; 69 if(L==R || tree[rt].v!=0){ // 如果到了叶子 就不再往下走了,就算是计算了这个叶子的编号v 可能是0 但是我们最后统计答案的时候是从flag[1~n] 所以无影响 70 flag[tree[rt].v] = 1; 71 return ; 72 } 73 74 pushdown(rt); 75 int mid = (L+R)/2; 76 if(l<=mid) query(rt<<1,l,r); 77 if(r>mid) query(rt<<1|1,l,r); 78 } 79 80 int main(){ 81 int T = read(); 82 while(T--){ 83 H.clear(),p.clear(); 84 int n = read(); 85 for(int i=0; i<=n; i++) flag[i] = 0; 86 for(int i=0; i<n; i++){ 87 q[i].x = read(), q[i].y = read(); 88 p.push_back(q[i].x); 89 p.push_back(q[i].y); 90 } 91 sort(p.begin(),p.end()); 92 p.erase(unique(p.begin(),p.end()),p.end()); 93 for(int i=0; i<(int)p.size(); i++){ 94 H[p[i]] = i+1; 95 } 96 97 build(1,1,p.size()); 98 for(int i=0; i<n; i++) 99 update(H[q[i].x],H[q[i].y],1,i+1); 100 query(1,1,p.size()); 101 int ans = 0; 102 for(int i=1; i<=n; i++) 103 if(flag[i]) 104 ans++; 105 cout << ans << endl; 106 } 107 108 return 0; 109 }