POJ - 2528 Mayor's posters (线段树,离散处理)

题意:给出一个很大的范围(1 <= ri <= 10000000.)表示所给出的m次询问修改中会出现在这个范围中,问最后能够看到的完整海报数

思路:看到这么大的范围我们就会思考离散化数据,离散化说的高大上实际上就是压缩所给出的数据空间。因为所给出的数据不会布满(1至1e7)所以就把空白处的空间压成一个,其他连续的空间保留

注意的是,不连续的空间压缩时要增加空白空间作为间隙

 

完整代码:

#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1e5;
const int inf = 0x3f3f3f3f;
int seg[maxn<<2];
int lazy[maxn<<2];
int arr[maxn],ans[maxn];
int last;
int L[maxn],R[maxn];//存储询问左右范围
int tot ;
int Dseg[maxn];//压缩后的segment tree

void push_up(int p){
    if(seg[p<<1] == seg[p<<1|1])
        seg[p] = seg[p<<1];
    else seg[p] = inf;
}
void push_down(int p,int l,int r){
    if(lazy[p]!= inf){
        lazy[p<<1] = lazy[p];
        lazy[p<<1|1] = lazy[p];
        seg[p<<1] = lazy[p];
        seg[p<<1|1] = lazy[p];
        lazy[p] = inf;
    }
}
void build(int p,int l,int r){
    if(l==r){
        seg[p] = arr[l];
        return ;
    }
    int mid = (l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    push_up(p);
}
void update(int p,int l,int r,int ql,int qr,int v){
    if(ql<=l&&r<=qr){
        seg[p] = v;
        lazy[p] = v;
        return ;
    }
    push_down(p,l,r);
    int mid = (l+r)>>1;
    if(ql <=mid) update(p<<1,l,mid,ql,qr,v);
    if(qr > mid) update(p<<1|1,mid+1,r,ql,qr,v);
    push_up(p);
}
void query(int p,int l,int r,int ql,int qr){
    if(seg[p]!=inf){
        if(seg[p]!= last) ans[seg[p]]++;
        last = seg[p];
        return ;
    }
    if(l==r) {last = inf; return ;}
    int mid = (l+r)>>1;
    push_down(p,l,r);
    query(p<<1,l,mid,ql,qr);
    query(p<<1|1,mid+1,r,ql,qr);
}
int main(){
    int n,T;
    cin>>T;
    while(T--){
        tot = 0;
        cin>>n;
        if(!n) cout<<0<<endl;
        //由于每次都会有区间覆盖问题,所以这里相当于记录更新数据
        else{
            for(int k = 0;k<n;k++){
                cin>>L[k]>>R[k];
                Dseg[tot++] = L[k];
                Dseg[tot++] = R[k];
            }
            //离散处理
            sort(Dseg,Dseg+tot);
            int len = unique(Dseg,Dseg+tot) - Dseg;
            int size = len;
            for(int i=1; i<size;i++){
                //左右区间不连续,就增加空白区间(取比前一个空间大1)
                if(Dseg[i] - Dseg[i-1]>1) Dseg[len++] = Dseg[i-1]+1;
            }
            sort(Dseg,Dseg+len);
            for(int i = 0;i<n ; i++){
                //再把离散好的重新存入L,R数组中
                L[i] = lower_bound(Dseg,Dseg + len ,L[i]) - Dseg +1;
                R[i] = lower_bound(Dseg,Dseg + len ,R[i]) - Dseg +1;
            }
            memset(lazy,inf,sizeof(lazy));
            memset(arr,inf,sizeof(arr));
            memset(ans,0,sizeof(ans));

            build(1,1,len);
            for(int i=0 ;i< n;i++){
                update(1,1,len,L[i],R[i],i+1);
            }
            last = inf; 
            //统计海报个数(也可以说是统计颜色)
            query(1,1,len,1,len);
            int cnt = 0;
            for(int i= 1;i <= len;i++){
                if(ans[i]) cnt++;
            }
            cout<<cnt<<endl;
        }
    }
}

 

上一篇:Java经典编程题50道之十四


下一篇:POJ - 2528 区间离散化,线段树区间修改,区间询问