poj2528线段树+数据离散化

来源:互联网 发布:淘宝上买电视可靠吗 编辑:程序博客网 时间:2024/05/29 02:08

离散化

转自:http://www.cnblogs.com/kevince/p/3893531.html

离散化,就是把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。

比如给你n个数:98998988,32434234,433234556,32434234,8384733,……

让你统计其中每个数出现的次数,传统的做法有好几种,比如一遍一遍的扫过去,比对叠加,这样算法的效率是O(n2),效率低下;

再比如先排序,再统计连续的相同的个数,这里的效率已经有所提高了,不过假如上面的数据是一道线段树的题目给出的数据,那么建树需要的空间开销实在是太大了。

再改进一下,采用哈希的方法,开一个大于其中最大数的数组并初始化为零,O(n)扫一下,在该数字对应的下标的元素上+1,如果对于比较小的数字还好说,但是对于上面出现的数字直接采用哈希对空间的开销是十分大的也是没有必要的,所以这里用到了数据的离散化。

首先将数字排序:32434234,32434234,43324556,8384733,98998988

去重后给予其对应的索引:0,0,1,2,3分别对应每个数,就可以简化很多操作,减少了很多不必要的资源开销。

除了对于较大整数需要使用离散化之外,对于一些需要使用整型数据结构,但给出的数据却是小数的也可以使用离散化,将其索引为整数就可以了。

那么可以总结出离散化的步骤:

1、排序

2、去重

3、索引

为了简化代码,我们采用STL算法离散化:


int a[n], b[n], sub[n];//a[n]是即将被离散化的数组,b[n]是a[n]的副本,sub用于排序去重后提供离散化后的值


sort(sub, sub + n);


int size = unique(sub, sub + n) - sub;


for(int i =0; i < n; i++) a[i]= lower_bound(sub, sub + size, a[i])- sub;//即a[i]为b[i]离散化后对应的值


题解:

转自:https://www.cnblogs.com/wuyiqi/archive/2012/03/19/2405885.html

题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报
思路:这题数据范围很大,直接搞超时+超内存,需要离散化:
离散化简单的来说就是只取我们需要的值来用,比如说区间[1000,2000],[1990,2012] 我们用不到[-∞,999][1001,1989][1991,1999][2001,2011][2013,+∞]这些值,所以我只需要1000,1990,2000,2012就够了,将其分别映射到0,1,2,3,在于复杂度就大大的降下来了
所以离散化要保存所有需要用到的值,排序后,分别映射到1~n,这样复杂度就会小很多很多
而这题的难点在于每个数字其实表示的是一个单位长度(并且一个点),这样普通的离散化会造成许多错误(包括我以前的代码,poj这题数据奇弱)
给出下面两个简单的例子应该能体现普通离散化的缺陷:
1-10 1-4 5-10
1-10 1-4 6-10
为了解决这种缺陷,我们可以在排序后的数组上加些处理,比如说[1,2,6,10]
如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了.

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn  = 100000;
bool ha[maxn];
int col[maxn*4];
struct node
{
    int l,r;
}q[maxn];
int ans;
int x[maxn*2];
void pushdown(int rt)
{
    if(col[rt] != -1)
    {
        col[rt*2] = col[rt *2+1] = col[rt];
        col[rt] = -1;
    }
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l && r<=R)
    {
        col[rt] = c;
        return;
    }
    pushdown(rt);
    int mid = (r+l)>>1;
    if(L<=mid)
        update(L,R,c,l,mid,rt*2);
    if(R > mid)
        update(L,R,c,mid+1,r,rt*2+1);
}
void query(int l,int r,int rt)
{
    if(col[rt]!=-1)
    {
        if(!ha[col[rt]])
            ans++;
        ha[col[rt]] = true;
        return;
    }
    if(l == r)
        return ;
    int mid = (r+l)>>1;
    query(l,mid,rt*2);
    query(mid+1,r,rt*2+1);
}
int main()
{
    int n,t,i,j;
    scanf("%d",&t);
    while(t--)
    {
        int cnt = 0;
        scanf("%d",&n);
        for(i = 0; i < n; i++)
        {
            scanf("%d%d",&q[i].l,&q[i].r);
            x[cnt++] = q[i].l;
            x[cnt++] = q[i].r;
        }
        sort(x,x+cnt);
        int m = 1;
        for(i = 1; i < cnt; i++)
            if(x[i] != x[i-1])
                x[m++] = x[i];
        for(i = m-1; i > 0; i--)
            if(x[i] != x[i-1]+1)
                x[m++] = x[i-1]+1;
        sort(x,x+m);
        memset(col,-1,sizeof(col));
        for(i = 0; i < n; i++)
        {
            int l = lower_bound(x,x+m,q[i].l)-x;
            int r = lower_bound(x,x+m,q[i].r)-x;
            update(l,r,i,0,m,1);
        }
        memset(ha,0,sizeof(ha));
        ans = 0;
        query(0,m,1);
        printf("%d\n",ans);
    }
    return 0;
}