poj 2528 Mayor's posters 线段树区间更新 + 离散化

题目链接:

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 }

 

posted @ 2017-03-01 23:56  _yxg123  阅读(139)  评论(0编辑  收藏  举报