poj2528 Mayor's posters 线段树,成段更新,离散化

13 篇文章 0 订阅
13 篇文章 0 订阅

题目链接:http://poj.org/problem?id=2528

大致题意:

有一面墙,被等分为1QW份,一份的宽度为一个单位宽度。现在往墙上贴N张海报,每张海报的宽度是任意的,但是必定是单位宽度的整数倍,且<=1QW。后贴的海报若与先贴的海报有交集,后贴的海报必定会全部或局部覆盖先贴的海报。现在给出每张海报所贴的位置(左端位置和右端位置),问张贴完N张海报后,还能看见多少张海报?(PS:看见一部分也算看到。)


这道题看了小优师姐的博客和HH大牛的博客,总算搞懂了。。。看懂后自己写了一遍代码,A掉

///2014.6.4
///poj2528

//1660K   94MS

/**
 *离散化 + 线段树
 */

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

#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1

#define maxn 12000

int segT[maxn<<4];   //线段树数组,叶子节点数最多为 2*maxn 个
int li[maxn];
int ri[maxn];
int hash[maxn<<3];  //数组内容为区间端点,而下标对应离散化后对应的点
bool used[maxn];    //标记该张海报是否已经算过
int num;            //最终结果

void PushDown(int rt){
    if( segT[rt] != -1 ){
        segT[rt<<1] = segT[rt<<1|1] = segT[rt];
        segT[rt] = -1;
    }
}
void update(int L,int R,int c,int l,int r,int rt){
    if( L<=l && r<=R ){
        segT[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( segT[rt] != -1 ){
        if( !used[ segT[rt] ] )num++;
        used[ segT[rt] ] = true;
        return ;
    }
    if( l == r ) return;
    int m = (l+r)>>1;
    query(lson);
    query(rson);
}
int binsearch(int hash[],int n,int x){  //折半查找确定离散化后对应的点
    int l=0,r=n-1;
    while( l<=r ){
        int m = (l+r)>>1;
        if( hash[m] < x )
            l = m+1;
        else if( hash[m] > x )
            r = m-1;
        else
            return m;
    }
    return -1;
}
int main(){
    // freopen("in","r",stdin);
    // freopen("out","w",stdout);

    int T,n;
    scanf("%d",&T);
    while( T-- ){
        scanf("%d",&n);
        int nn=0;
        for(int i=0 ; i<n ; i++){
            scanf("%d%d",&li[i],&ri[i]);
            hash[nn++] = li[i];
            hash[nn++] = ri[i];
        }
        sort(hash,hash+nn);
        int m = 1;
        for(int i=m ; i<nn ; i++){  //踢出重复的点
            if( hash[i] != hash[i-1] )
                hash[m++] = hash[i];
        }
        for(int i=m-1 ; i>0 ; i--){  //在每个点后新加一个其后的点,保证不会因为离散化而压缩掉本来应该存在的区间
            if( hash[i] != hash[i-1]+1 )
                hash[m++] = hash[i]+1;
        }
        sort(hash,hash+m);
        memset(segT , -1 , sizeof(segT));
        for(int i=0 ; i<n ; i++){
            int l = binsearch(hash,m,li[i]);
            int r = binsearch(hash,m,ri[i]);
            update(l,r,i,0,m-1,1);
        }
        num = 0;
        memset(used,false,sizeof(used) );
        query(0,m-1,1);
        printf("%d\n",num );
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值