poj 2528 贴海报

题意:有一面墙,然后在上面贴海报,最后看一共能看到几张海报。

思路:本来以为是简单的线段树,但是搞了许久未果。。。  然后上网看了看,才知道这是离散化+hash+线段树

因为题给的,长度的范围比较大,但是给出的海报张数却不是很多。。。

离散化我也是第一次看,我感觉就是把一些数换一种映射方式,但是数据之间的关系(比如:大小)是不变的。

这道题就是把海报的范围,进行排序,去重,映射成了X数组的下标 

1 4

2 6

8 10

3 100000

X-- 1 2 3 4 6 8 100000

然后100000就可以映射成6 ,这里还是不明白HH 的线段树中为什么要对相邻之间相差1 的X 进行处理,以后有新的理解的时候,还要再写写。。继续膜拜hh  Orz...


比如 

1 10

1 3

6 10  这组数据

如果普通的离散化  是 {1,3,6,10} 对应{0,1,2,3}

[0,3]

[0,1] [2,3]

[0,0]     [1,1]  [2,2]  [3,3]  线段树是这样的  那么 1 10  就会被完全覆盖。


所以应该特殊处理   如果相邻数字间距大于1的话 那么就插入一个数,避免这种情况的发生 离散化的结果{1,2,3,4,6,7,10}

如果以后还有新的理解  继续补充!!!


#include<iostream>
#include<algorithm>
using namespace std;
#define lson l , m , rt<<1
#define rson m + 1 , r , rt<<1|1
const int maxn = 10005;
int li[maxn],ri[maxn];
int col[maxn<<4];
bool hash[maxn<<4];
int X[maxn*3];
int cnt;
void PushDown(int rt) {
    if (col[rt]!=-1) {
		//printf("rt=%d\n",rt);
        col[rt<<1] = col[rt<<1|1] = col[rt];    
        col[rt] = -1;//传递结束记得还原 
    }    
}
void update(int L,int R,int i,int l,int r,int rt) {
    if (L <= l&&R >= r) {
        col[rt] = i;// 成段更新 
        return ;    
    }    
    PushDown(rt);
    int m = (l + r) >> 1;
    if (m >= L) update(L , R , i , lson);
    if (m < R) update(L , R , i , rson);
}
int Bin(int key,int n,int X[]) {//二分找key 对应的下标m 
    int l , r;
    l = 0 , r = n - 1;
    while (l <= r) {
        int m = (l + r) >> 1;
        if (X[m] == key) return m;
        if (key >= X[m]) l = m + 1;
        else r = m - 1;
    }    
    return -1;
}
void query(int l,int r,int rt) {//相当于遍历一次线段树吧 
    if (col[rt] != -1) {//加入hash判断 就能保证用同一种懒惰标记的,也就是颜色相同的区域不用重复判断 
        if (!hash[col[rt]]) {
			//printf("rt==%d\n",rt);
			cnt ++;
		}
        hash[ col[rt] ] = true;    
        return ;
    }
    if (l == r) return;
    int m = (l + r) >> 1;
    query(lson);
    query(rson);
}
int main() {
    int T , n;
    scanf("%d",&T);
    while (T --) {
        scanf("%d",&n);
        int g = 0;
        for (int i = 0 ; i < n ; i ++) {
            scanf("%d%d",&li[i],&ri[i]);
            X[g++] = li[i];
            X[g++] = ri[i];    
        } 
        sort(X , X + g);
        int m = 1;
        for (int i = 1 ; i < g ; i ++) {
            if (X[i] != X[i-1]){
				X[m++] = X[i];
			 }       
        }
        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 = Bin(li[i] , m , X);
            int r = Bin(ri[i] , m , X);
            //printf("l=%d , r=%d\n",l,r);
            update(l , r , i , 0 , m , 1);       
        }   
        memset(hash,false,sizeof(hash));
        cnt = 0;
        query(0 , m , 1);
        printf("%d\n",cnt);
    }    
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值