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

时间:2022-04-17 12:14:32

题意 : 在墙上贴海报, n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000)。求出最后还能看见多少张海报。

 

分析 : 很容易想到利用线段树来成段置换,最后统计总区间不同数的个数。但是这里有一个问题,就是区间可以很大,线段树开不了那么大的空间,遂想能不能离散化。实际上只记录坐标的相对大小进行离散化最后是不影响我们计算的,但是光是普通的离散化是不行的,就是我们贴海报的实际意义是对(l, r)段进行添加,而不是对于这个区间的点进行添加,是段树不是点树,如果这样普通离散化的话就会出现一个问题,比如数据1-10、1-4、6-10 行的,我们离散化后是1-4、1-2、3-4 ,不离散的结果是 3 但是离散化后再计算就是 2 了!原因就是我们是成段更新而不是点更新,进行添加海报的(l, r)的意义是对这一段进行添加,而离散化之后将原本不相邻的点变成了相邻的点,就导致了上面例子 4 - 6被覆盖了!解决这个问题的方法就是,在离散化的时候,将原本不相邻的两个点中间添加一个数,来表示中间是有“缝隙”的。

AC代码:

POJ2528 Mayor's posters(线段树+离散化)POJ2528 Mayor's posters(线段树+离散化)
#include <cstdio>

#include <cstring>

#include <algorithm>

using namespace std;

#define lson l , m , rt << 1

#define rson m + 1 , r , rt << 1 | 1
const int maxn =  21112;
bool hash[maxn];
int li[maxn] , ri[maxn];
int X[maxn<<3];
int col[maxn<<4];
int cnt;

void PushDown(int rt) {

         if (col[rt] != -1) {

                 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 ;

         }
         PushDown(rt);

         int m = (l + r) >> 1;

         if (L <= m) update(L , R , c , lson);

         if (m < R) update(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 Bin(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;

                 else r = m - 1;

         }

         return -1;

}

int main() {

         int T , n;

         scanf("%d",&T);

         while (T --) {
          // memset (col,0,sizeof(col));
                 scanf("%d",&n);

                 int nn = 0;

                 for (int i = 0 ; i < n ; i ++) {

                          scanf("%d%d",&li[i] , &ri[i]);
                          X[nn++] = li[i];///记录所有出现的点
                          X[nn++] = ri[i];

                 }
                 sort(X , X + nn);
                 int m = unique(X,X+nn)-X;///去重
                 ///在不相邻的点中间添加一个数
                 for (int 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 (int i = 0 ; i < n ; i ++) {
                          int l = lower_bound(X,X+m,li[i])-X;////在离散化之后的坐标系arr中寻找左端点
                          int r = lower_bound(X,X+m,ri[i])-X;
                          //   int l = Bin(li[i] , m , X);
                          //int r = Bin(ri[i] , m , X);
                          update(l , r , i , 0 , m , 1);
                 }
                 cnt = 0;
                 memset(hash , false , sizeof(hash));
                 query(0 , m , 1);
                 printf("%d\n",cnt);

         }

         return 0;

}
View Code