poj2528 线段树+离散化

原创 2012年03月22日 22:32:10

题意:n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000)。

      求出最后还能看见多少张海报。

输入:

1
5
1 4
2 6
8 10
3 4
7 10

解法:离散化,如下面的例子(题目的样例),因为单位1是一个单位长度,将下面的

      1   2   3   4  6   7   8   10

     —  —  —  —  —  —  —  —

      1   2   3   4  5   6   7   8

离散化  X[1] = 1; X[2] = 2; X[3] = 3; X[4] = 4; X[5] = 6; X[7] = 8; X[8] = 10

于是将一个很大的区间映射到一个较小的区间之中了,然后再对每一张海报依次更新在宽度为1~8的墙上(用线段树),最后统计不同颜色的段数。

但是只是这样简单的离散化是错误的,

如三张海报为:1~10 1~4 6~10

离散化时 X[ 1 ] = 1, X[ 2 ] = 4, X[ 3 ] = 6, X[ 4 ] = 10
第一张海报时:墙的1~4被染为1;
第二张海报时:墙的1~2被染为2,3~4仍为1;
第三张海报时:墙的3~4被染为3,1~2仍为2。
最终,第一张海报就显示被完全覆盖了,于是输出2,但实际上明显不是这样,正确输出为3。

新的离散方法为:在相差大于1的数间加一个数,例如在上面1 4 6 10中间加5(算法中实际上1,4之间,6,10之间都新增了数的)

X[ 1 ] = 1, X[ 2 ] = 4, X[ 3 ] = 5, X[ 4 ] = 6, X[ 5 ] = 10

这样之后,第一次是1~5被染成1;第二次1~2被染成2;第三次4~5被染成3

最终,1~2为2,3为1,4~5为3,于是输出正确结果3。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

#define M 10005

int m, li[M], ri[M];
int x[M<<3], col[M<<4], ans;
bool hash[M];

void PushDown(int rt) {
     col[rt<<1] = col[rt<<1|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;
     }

     if (col[rt] != -1) PushDown(rt);
     int m = (l + r) >> 1;
     if (m >= L) Update(L, R, c, l, m, rt<<1);
     if (m < R)  Update(L, R, c, m+1, r, rt<<1|1);
}

void query(int l, int r, int rt) {
    if (l == r) {
        if (!hash[col[rt]]) {
        ans++;
        hash[col[rt]] = true;
       }
       return;
    }
    if (col[rt] != -1) PushDown(rt);
    int m = (l + r) >> 1;
    query(l, m, rt<<1);
    query(m+1, r, rt<<1|1);
}

int BSearch(int ll, int hh, int xx) {
    int mm;

    while (ll <= hh) {
        mm = (ll + hh) >> 1;
        if (x[mm] == xx) return mm;
        else if (x[mm] > xx)  hh = mm - 1;
        else ll = mm + 1;
    }
    return -1;
}

int main()
{
    int t, n, i;

    scanf ("%d", &t);
    while (t--) {
        memset(col, -1, sizeof (col));
        memset (hash, false, sizeof (hash));
        int nn = 0;
        scanf ("%d", &n);
        for (i = 1; i <= n; i++) {
             scanf ("%d %d", &li[i], &ri[i]);
             x[++nn] = li[i];
             x[++nn] = ri[i];
        }
        sort(x+1, x+nn+1);
        m = 1;
        for (i = 2; i <= nn; i++) {
             if (x[i] != x[i-1]) x[++m] = x[i];
        }
        for (i = m; i > 1; i--) {
            if (x[i] - x[i-1] > 1) x[++m] = x[i] - 1;
        }
        sort(x+1, x+m+1);
        for (i = 1; i <= n; i++) {
            int l = BSearch(1, m, li[i]);
            int r = BSearch(1, m, ri[i]);
            Update(l, r, i, 1, m, 1);
        }
        ans = 0;
        query(1, m, 1);
        printf("%d\n", ans);
    }
    return 0;
}


然后再提一下我自己关于二分理解(对二分总是理解不透彻,需要慢慢积累):

最初二分写成这样的,老是错:

int BSearch(int ll, int hh, int xx) {
    int mm;

    while (ll < hh) {
        mm = (ll + hh) >> 1;
        if (x[mm] == xx) return mm;
        else if (x[mm] > xx)  hh = mm;
        else ll = mm + 1;
    }
    return -1;
}
后来理解之后,才发现,这样写,只能搜索在区间[ll,hh)的数,注意,右边是开区间,而此题正好需要搜索右边的闭区间,所以错了。

之前的思想以及代码参考:神牛博客

http://www.notonlysuccess.com/index.php/segment-tree-complete/


poj2528--Mayor's posters(线段树+离散化)

Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 41785 ...
  • u013015642
  • u013015642
  • 2014年08月08日 19:50
  • 3051

POJ2528【线段树经典染色。】

来一点转的线段树精髓: 1、 线段树是二叉树,且必定是平衡二叉树,但不一定是完全二叉树。 2、 对于区间[a,b],令mid=(a+b)/2,则其左子树为[a,mid],右子树为[mid+1,b],当...
  • water__er
  • water__er
  • 2013年08月25日 10:06
  • 2337

POJ2528-Mayor's posters

转载请注明出处:優YoU http://blog.csdn.net/lyy289065406/article/details/6799170   大致题意: 有一面墙,被等分为1QW份,一份的宽...
  • lyy289065406
  • lyy289065406
  • 2011年09月22日 07:13
  • 9686

POJ2528:Mayor's posters(线段树区间更新+离散化)

Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral electi...
  • libin56842
  • libin56842
  • 2013年10月31日 15:52
  • 4422

pku2528----区间染色成段更新

//   Creat   By  郭仔    2012年3月29日10:16:59 区间染色的变形,不过比区间染色问题要难一些~ 用到区间染色成段更新,hash,离散化,蛋疼的...
  • guoxianzhuang
  • guoxianzhuang
  • 2015年03月29日 10:20
  • 1021

poj 2528 Mayor's posters(离散化+线段树)

http://poj.org/problem?id=2528 题意: 市长竞选,每个市长都往墙上贴海报,海报之间彼此可以覆盖,给出粘贴顺序和每个海报的起点和终点,问最后又多少海报时可见的。 刚接触...
  • u013081425
  • u013081425
  • 2014年02月10日 19:11
  • 1103

poj2528 线段数组 离散化

poj2528 线段数组 离散化 #include #include #include using namespace std; #define lson l , m , rt ...
  • liyanfeng1996
  • liyanfeng1996
  • 2016年10月25日 22:30
  • 271

poj2528离散化处理数据 线段树

#include #include #include #include #include #include #include #include #include #include ...
  • u012432475
  • u012432475
  • 2015年06月04日 00:23
  • 430

poj2528(离散化,线段树成段覆盖)

题目链接:poj2258 学习离散化的一个好题。。。 /*poj 2258 Mayor's posters 离散化,成段覆盖 题目大意: 不断的有海报覆盖在以前的海报上,求能看到几张海报 思路: 因...
  • u010728156
  • u010728156
  • 2013年12月04日 19:22
  • 1240

poj2528(贴海报)线段树离散化

//poj2528贴海报(线段树离散化) #include #include #include #include using namespace std; const int maxn=100005...
  • zizahn
  • zizahn
  • 2016年09月16日 14:14
  • 224
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:poj2528 线段树+离散化
举报原因:
原因补充:

(最多只允许输入30个字)