poj 2528 线段树-区间更新 离散化

这道题很久以前就尝试做了,后来因为那时候离散化一窍不通于是退而却步。

之后做到扫描线必须用到离散化,于是才狠下心来把离散化端了。

引用Accepted的博客的一句话“你若不想做,你会找借口;你若想做,你会找办法”。


首先讲离散化,所谓的离散化,在我看来,就是把题目中有意义的点的值抽取出来,过滤掉无意义的点,以达到节省空间甚至时间的目的。

例如我们这道题直接开数组是impossible的。所以离散是必然的选择。

在本题里,离散第一步是先把所有有用的点抽取出来放到一个数组里。

For example:对于下面这个样例

5
1 4
2 6
8 10
3 4
7 10
我们抽取1 2 3 4 6 7 8 10这8个数

但是仅用这8个端点数是不符合本题的,因为正如胡浩大牛所说的那样:

普通的离散化会造成许多错误

给出下面两个简单的例子应该能体现普通离散化的缺陷:
例子一:1-10 1-4 5-10
例子二:1-10 1-4 6-10

普通离散化后都变成了[1,4][1,2][3,4]
线段2覆盖了[1,2],线段3覆盖了[3,4],那么线段1是否被完全覆盖掉了呢?
例子一是完全被覆盖掉了,而例子二没有被覆盖  

我的代码的离散化和胡浩大牛的离散化貌似有点不同,我学习的是Accepted博客的离散化。

还是拿上面两个例子,如果是我的一般的离散化的话,线段树里头就只有1 4 5 10(1 4 6 10)这4个点,将例一、例二的三条边分别加进去也会造成无法判断是否覆盖的问题。

又由于题目的每一个值代表着一个单位长度的线段,所以对于这种覆盖bug只会出现在给出的两个单位长度的线段之间还有其他线段的情况。

所以,我们只要在两个不相邻的线段间再多加一线段即可解决这问题。

附上自制低质量插图(上面是例一,最后只能看到2个海报,下面是样例二,最后应该能看到3个,但是普通离散化会把中间的第5个单位线段所表示的海报1“沉默”掉。

//插科打诨一下,不知道有没有人和我有这个相同的疑问:会不会存在一组数据使得 某一个额外加的线段 与 (离散化后)与之相邻的线段 之间的线段再次“沉默”掉,使的我们要加更多的边以防止这种再次“沉默”?For example,即有无一组数据使得1 4 (6) 10 20 中 6与10 或者 4与(6)中间的线段被再次“沉默”?

答案必然是否定的,因为我AC了((/ □ \)这算哪门子答案)

由于这个二次被沉默的线段隔壁必然是一次被沉默线段,所以如果出现二次沉默,则必然有一个数据包含一次沉默这个单位线段,而实际上这个线段是数据没有给出的。所以二次沉默不存在

插科打诨完毕//

另外,还要注意一下记录离散化的数组规模。(我因为这个RT了3,4次……)


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#define lson l , mid , dex<<1
#define rson mid+1, r, dex<<1|1
#define havemid int mid = (l + r)>>1
using namespace std;
const int mx = 10100;
map<int , int> q;
struct po
{
    int a,b;
    int key;//The id of the poster
}point[mx];
struct se
{
    int l,r;
    int key;
    bool flag;//Lazy flag
}seg[mx<<4];
int ini_data[mx<<1];
int aft_data[mx<<2];
void Push_down(int dex)
{
    if(seg[dex].flag)
    {
        seg[dex<<1].flag = seg[dex<<1|1].flag = true;
        seg[dex<<1].key = seg[dex<<1|1].key = seg[dex].key;
        seg[dex].flag = false;
    }
}
void build(int l, int r, int dex)
{
    seg[dex].l = aft_data[l];
    seg[dex].r = aft_data[r];
    seg[dex].key = -1;
    seg[dex].flag = false;
    if(l == r) return;
    havemid;
    build(lson);
    build(rson);
}
void query(int l, int r, int dex, int& ans)
{
    if(seg[dex].l == seg[dex].r)
    {
        if(q[seg[dex].key] == 0 && seg[dex].key != -1)
        {
            ans++;
            q[seg[dex].key] = 1;
        }
        return;
    }
    Push_down(dex);
    havemid;
    query(lson, ans);
    query(rson, ans);
}
void updata(int L, int R, int id, int l, int r, int dex)
{
    if(R < seg[dex].l || L > seg[dex].r)  return;
    if(L<=seg[dex].l && R>=seg[dex].r)
    {
        seg[dex].key = id;
        seg[dex].flag = true;
        return;
    }
    Push_down(dex);
    havemid;
    updata(L, R, id, lson);
    updata(L, R, id, rson);
}
int main()
{
//    freopen("2528.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        q.clear();
        int n;
        scanf("%d",&n);
        int tem = 0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d",&point[i].a,&point[i].b);
            point[i].key = i;
            ini_data[++tem] = point[i].a;
            ini_data[++tem] = point[i].b;
        }

        //Disperse the segmemt
        sort(&ini_data[1] , &ini_data[tem+1]);
        int w = 0;
        ini_data[0] = -1;
        for(int i=1; i<=tem; i++)
            if(ini_data[i] != ini_data[i-1])
                ini_data[++w] = ini_data[i];
        tem = w;
        w = 0;
        aft_data[++w] = ini_data[1];
        for(int i=2; i<=tem; i++)
        {
            if(ini_data[i] > ini_data[i-1] + 1)
            {
                aft_data[++w] = ini_data[i] - 1;
                aft_data[++w] = ini_data[i];
            }
            else
                aft_data[++w] = ini_data[i];
        }

        build(1,w,1);
        for(int i=1; i<=n; i++)
            updata(point[i].a, point[i].b, point[i].key, 1, w, 1);
        int ans = 0;
        query(1, w ,1, ans);
        printf("%d\n",ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值