zoukankan      html  css  js  c++  java
  • poj 2528 线段树+离散化

    题目链接:http://poj.org/problem?id=2528

    题意:

        在墙上贴海报,输入n(1<=n<=10000),表示n张海报,后n行输入 两整数l,r  ( 1<= l, r<= 1e9 ),表示海报从编号为l的石头一直贴到编号为r的石头,输入顺序即为粘贴顺序。问n张贴完之后,还能看到多少张海报。

    思路:

          显然区间操作,很容易联想到线段树操作,只不过区间 l,r 最大范围可达1e9,直接建树,内存必爆。   那么就需要避开1e9的数据,进行离散化,将区间变成(1到n)

          至于如何离散化,原理是映射+压缩。 

      

    样例:
    1
    5 1 4 2 6 8 10 3 4 7 10
     1 4 2  6 8 10 3 4 7 10
    排序+去重   :    1  2  3  4  6  7  8  10    存入x数组
    对上数组进行编号  1  2  3  4  5  6  7  8     即x【1】=1    x【2】=2    x【5】=6    x【8】=10    (即对原数组进行压缩)

    本题特殊的一点:需要中间插值

    设一个样例
    
    3
    1 10
    1 3
    5 10
    
    
    进行离散化:
            1    3    5    10
    编号:
            1    2    3    4
    
    
    依次贴海报
            1    10    对应的是  1  4
            1    3       对应的是  1    2
            5     10                   3    4
    
    显然 依次贴【1,4】   【1,2】  【3,4】
           显然第一张海报【1,4】被覆盖,即答案为:2
    
    但是实际答案为3。
    
    
    至于如何解决:
    
       中间插值 (即对两个相邻数字,相差大于1的插入某值)
    
    进行中间插值离散化:
            1  2  3   4   5   6  10
    编号:
            1  2  3   4   5   6   7
    
    
    这时答案为3

    AC代码:

    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map> 
    #include<algorithm>
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    #define Mem0(x) memset(x,0,sizeof(x))
    #define Mem1(x) memset(x,-1,sizeof(x))
    #define MemX(x) memset(x,0x3f,sizeof(x))
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f;
    const double pi=acos(-1.0);
    
    const int MAXN=10010;
    struct Tree{
        int l,r,lazy;
    }tree[MAXN<<4];
    
    struct s{
        int l,r;
    }a[MAXN<<4];
    int x[MAXN<<4];
    bool hash[MAXN<<4];
    int n,ans;
    
    void pushdown(int rt)
    {
        tree[rt<<1].lazy=tree[rt<<1|1].lazy=tree[rt].lazy;
        tree[rt].lazy=-1;
    }
    void update(int left,int right,int c,int l,int r,int rt)
    {
        if (l>=left&&r<=right){
            tree[rt].lazy=c;
            return ;
        }
        if (tree[rt].lazy!=-1)
            pushdown(rt);
        int mid=(l+r)>>1;
        if (mid>=left)
            update(left,right,c,l,mid,rt<<1);
        if (mid<right)
            update(left,right,c,mid+1,r,rt<<1|1);
        return ;
    }
    
    void query(int l,int r,int rt)
    {
        if (l==r){
            if (!hash[tree[rt].lazy]){
                ans++;
                hash[tree[rt].lazy]=true;
            }
            return ;
        }
        if (tree[rt].lazy!=-1)
            pushdown(rt);
        int mid=(l+r)>>1;
        query(l,mid,rt<<1);
        query(mid+1,r,rt<<1|1);
    } 
    int main()
    {
        int n,t;
        scanf("%d",&t);
        while (t--){
            memset(tree,-1,sizeof(tree));
            memset(hash,false,sizeof(hash));
            int cnt=0;
            scanf("%d",&n);
            for (int i=1;i<=n;i++){
                scanf("%d%d",&a[i].l,&a[i].r);
                x[++cnt]=a[i].l;
                x[++cnt]=a[i].r;
            }
            sort(x+1,x+cnt+1);
            int size=unique(x+1,x+cnt+1)-x-1;  //离散化+去重 
            for (int i=size;i>1;i--){         //中间增值 
                if (x[i]-x[i-1]>1)    
                    x[++size]=x[i]-1;
            }
            sort(x+1,x+size+1);
            for (int i=1;i<=n;i++){
                int l=lower_bound(x+1,x+size+1,a[i].l)-x;   //二分查找的内库函数
                int r=lower_bound(x+1,x+size+1,a[i].r)-x;
                update(l,r,i,1,size,1);
            }
            ans=0;
            query(1,size,1);
            cout<<ans<<endl;
        }
        return 0;
    }
  • 相关阅读:
    yii2框架安装
    RabbitMq简单应用
    PHP扩展开发--编写一个helloWorld扩展
    node 笔记整理
    js 笔记整理
    JavaScript event loop事件循环 macrotask与microtask
    移动端 缩放插件备份
    vue 笔记备份
    echart 打开新世界的大门
    canvas 笔记整理
  • 原文地址:https://www.cnblogs.com/q1204675546/p/11279860.html
Copyright © 2011-2022 走看看