线段树线段覆盖(离散化+区间覆盖)

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

Input

       第一行: 样例个数T
       第二行: 贴海报的人n
       第三行: 每个人贴海报的范围
        接下来n行: 每个人贴海报的范围

Output

对于每一个输入,输出最后可以看到的海报张数。下面这个图是样例解释



Sample Input

1
5
1 4
2 6
8 10
3 4
7 10

Sample Output

4

这个题如果你用普通的离散化,是错的

如三张海报为:1~10 1~4 6~10

离散化时 X[ 1 ] = 1, X[ 2 ] = 4, X[ 3 ] = 6, X[ 4 ] = 10
第一张海报时:墙的1~4被染为1;
第二张海报时:墙的1~2被染为2,3~4仍为1;
第三张海报时:墙的3~4被染为3,1~2仍为2。
最终,第一张海报就显示被完全覆盖了,于是输出2,但实际上明显不是这样,正确输出为3。

新的离散方法为:在相差大于1的数间加一个数,例如在上面1 4 6 10中间加5(算法中实际上1,4之间,6,10之间都新增了数的)

X[ 1 ] = 1, X[ 2 ] = 4, X[ 3 ] = 5, X[ 4 ] = 6, X[ 5 ] = 10

这样之后,第一次是1~5被染成1;第二次1~2被染成2;第三次4~5被染成3

最终,1~2为2,3为1,4~5为3,于是输出正确结果3。

        for(int i=1;i<=n;i++){
            scanf("%d%d",&li[i],&ri[i]);
            lsh[++cnt]=li[i];
            lsh[++cnt]=ri[i];
        }    
        sort(lsh+1,lsh+cnt+1);
        int mm=unique(lsh+1,lsh+cnt+1)-(lsh+1);
        int nn=mm;
        for(int i=2;i<=nn;i++){
            if(lsh[i]-lsh[i-1]>1){
                lsh[++mm]=lsh[i-1]+1;
            }
        }
        sort(lsh+1,lsh+mm+1);

 


离散化之后就是线段树区间修改,和单点查询

建树修改+查询
     build(1,1,mm);
        for(int i=1;i<=n;i++){
            int x=lower_bound(lsh+1,lsh+mm+1,li[i])-lsh;
            int y=lower_bound(lsh+1,lsh+mm+1,ri[i])-lsh;
            update(1,x,y,i);
        } 
        for(int i=1;i<=mm;i++){
            int p=query(1,i);
            vis[p]++;
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            if(vis[i]){
                ans++;
            }
        } 
        cout<<ans<<endl;
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
/*
3
3 
1 10
1 4
6 10
*/
const int maxn=1e6+100;  
int lsh[maxn];
int li[maxn],ri[maxn];
int vis[maxn];
struct node{
    int l,r;
    int lazy;
}t[maxn];
int n;
int cnt=0;
void build(int p,int l,int r){
    t[p].l=l;
    t[p].r=r;
    t[p].lazy=0; 
    if(l==r){
        t[p].lazy=0;
        return ;
    }
    int mid=(t[p].l+t[p].r)/2; 
    build(p*2,l,mid);
    build(2*p+1,mid+1,r);
}
void upsh(int p){
    t[2*p].lazy=t[p].lazy;
    t[2*p+1].lazy=t[p].lazy;
    t[p].lazy=0;
}
void update(int p,int l,int r,int x){
    if(t[p].l>=l&&t[p].r<=r){
        t[p].lazy=x;
        return ;
    }
    if(t[p].lazy){
        upsh(p);
    }
    int mid=(t[p].l+t[p].r)/2;
    if(l<=mid){
        update(2*p,l,r,x);
    }
    if(r>mid){
        update(2*p+1,l,r,x);
    }
} 
int query(int p,int x){
    if(t[p].l==t[p].r){
        return t[p].lazy;
    }
    if(t[p].lazy){
        upsh(p);
    }
    int mid=(t[p].l+t[p].r)/2; 
    if(x<=mid){
        return query(2*p,x);
    }
    else{
        return query(2*p+1,x);
    }
}
int main(){
    int t;
    cin>>t;
    while(t--){
        cin>>n;
        memset(vis,0,sizeof(vis)); 
        cnt=0;
        for(int i=1;i<=n;i++){
            scanf("%d%d",&li[i],&ri[i]);
            lsh[++cnt]=li[i];
            lsh[++cnt]=ri[i];
        }    
        sort(lsh+1,lsh+cnt+1);
        int mm=unique(lsh+1,lsh+cnt+1)-(lsh+1);
        int nn=mm;
        for(int i=2;i<=nn;i++){
            if(lsh[i]-lsh[i-1]>1){
                lsh[++mm]=lsh[i-1]+1;
            }
        }
        sort(lsh+1,lsh+mm+1);
        build(1,1,mm);
        for(int i=1;i<=n;i++){
            int x=lower_bound(lsh+1,lsh+mm+1,li[i])-lsh;
            int y=lower_bound(lsh+1,lsh+mm+1,ri[i])-lsh;
            update(1,x,y,i);
        } 
        for(int i=1;i<=mm;i++){
            int p=query(1,i);
            vis[p]++;
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            if(vis[i]){
                ans++;
            }
        } 
        cout<<ans<<endl;
    }
}

 

posted @ 2021-03-06 15:17  lipu123  阅读(175)  评论(0编辑  收藏  举报