• 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 }
  • 相关阅读:
    C/C++位域(Bitfields)之我见(不错)
    C/C++位域(Bitfields)之我见(不错)
    C语言面试题之一——程序阅读题
    Matlab数据导入导出
    C语言大小端判断程序
    Qt——路径设置问题
    C语言大小端判断程序
    Qt——路径设置问题
    poj3625
    poj3660
  • 原文地址:https://www.cnblogs.com/yxg123123/p/6827661.html
Copyright © 2020-2023  润新知