poj 2528 Mayor's posters

来源:互联网 发布:数据挖掘会议 编辑:程序博客网 时间:2024/04/29 22:57

题目大意:

    往墙上贴海报,可以互相覆盖,问最终可以看到多少张海报?露出一部分的也算可以看到。

分析:

    由于本题数据比较大,因此处理时需要离散化,离散化是一种压缩区间的手段,可以降低复杂度。例如:[100,1000],[1010, 2012],[880, 2013];我们所需要的数据也就是100,1000,1010,2010,880,2013,对于[-∞,99],[101,879],[881,1009],[1011,20011],[2014,+]对我们来说都没有用,我们可以将其映射为1,2,3,4,5,6;复杂度就会大大降低,所以离散化要保存所有需要用到的值,排序后,分别映射到1--n,这样复杂度就会小很多很多。

    以本题为例:[1,4],[2, 6],[8, 10],[3, 4],[7, 10];现在我们取五个区间的十个端点,1,4,2,6,8,10,3,4,7,10;然后删除相同的端点4,10,剩下端点为:1,4,2,6,8,10,3,7,将其升序排列:1,2,3,4,6,7,8,10;

      1   2   3   4   6   7   8   10

   ↓      ↓     ↓      ↓      ↓     ↓     ↓       

   1   2   3   4   5   6   7    8


那么我们得到五个新的区间[1,4],[2, 5],[7,8],[3,4],[6, 8],而且所得五个新的区间,并没有改变其覆盖关系,如果数据很大的话,复杂度降低的会很明显。

    但是此种离散化有缺陷,例如:

    例子一:3 - 15 3 - 7 8 - 15
    例子二:3 - 15 3 - 7 9 - 15
    普通离散化后都变成了[1,4][1,2][3,4]例一完全被覆盖掉了,而例二没有被覆盖。为了解决这种缺陷,我们可以在排序后的数组上加些处理,比如说[1,2,6,10],如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了(参考:Not only success)

    离散化时有一点必须要注意的,就是必须先剔除相同端点后再排序,这样可以减少参与排序元素的个数,节省时间

#include <iostream>#include <cstring>#include <algorithm>#include <cstdio>#include <cstdlib>using namespace std;#define lson l, m, rt << 1#define rson m+1, r, rt << 1 | 1const int MAXN = 11111;bool hash[MAXN];int li[MAXN], ri[MAXN];int col[MAXN<<4];int X[MAXN*3];int cnt;void PushDown(int rt){if(col[rt] != -1){col[rt<<1] = col[rt<<1|1] = col[rt];col[rt] = -1;}}void Build(int l, int r, int rt){if( l == r ){return;}int m = (l+r)>>1;Build(lson);Build(rson);}void UpData(int L, int R, int c, int l, int r, int rt){if(L <= l && R >= r)//如果把每张海报都换成涂一种颜色,最后问可以看到多少种颜色,或许会好理解点{col[rt] = c;return;}PushDown(rt);int m = (l+r)>>1;if(L <= m)UpData(L, R, c,lson);if(R > m)UpData(L, R, c, rson);}void Query(int l, int r, int rt){if(col[rt] != -1){if( !hash[col[rt]] )cnt++;hash[col[rt]] = true;return;}if (l == r){return;}int m = (l+r)>>1;Query(lson);Query(rson);}int Binary_search(int key, int n, int X[]){int l = 0, r = n-1;while (l <= r){int m = ( l+r ) >> 1;if(X[m] == key)return m;if(X[m] < key)l = m+1;elser = m-1;}return -1;}int main(){int T, n, i;scanf("%d", &T);while(T--){scanf("%d", &n);int k = 0;for(i = 0; i < n; ++i){scanf("%d%d", &li[i], &ri[i]);X[k++] = li[i];X[k++] = ri[i];}sort(X, X+k);int m = 1;for(i = 1; i < k; ++i)//删除相同端点{if (X[i] != X[i-1]){X[m++] = X[i];}}for (i = m-1; i > 0; --i)//如果两个相邻端点之差大于1,则加一个数X[i-1]+1;解决上述缺陷{if (X[i] != X[i-1] + 1){X[m++] = X[i-1] + 1;}}sort(X, X+m);Build(0, m, 1);memset(col, -1, sizeof(col));for (i = 0; i < n; ++i){int l = Binary_search(li[i], m, X);//离散化实现int r = Binary_search(ri[i], m, X);UpData(l, r, i, 0, m, 1);}cnt = 0;memset(hash, false, sizeof(hash));Query(0, m, 1);printf("%d\n", cnt);}system("pause");return 0;}


原创粉丝点击