POJ 2528 线段树+离散化

//线段树的建树过程主要有两种形式,一种形式是
//            [1,3]
//         [1,2] [2,3] 
//另外一种形式是
//             [1,3]
//           [1,2] [3,3]
//         [1,1] [2,2] 
//本文用的是第二种形式,因为有【1,1】这种形式的存在 
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
using namespace std;

int c,n,left,right;
int i,j;

struct Node
{
    int left,right;
    int cover;
};
//存储线段树 
Node tree[20005*4];
int reg[20005][2];
int dis[10000005];
int ep[20005];
int flag[10005];

//创建线段树 
void build(int root,int l,int r){
    tree[root].left=l;
    tree[root].right=r;
    tree[root].cover=0;
    
    if(l==r)
        return;
    int mid=(l+r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
}
//向线段树中插入区间(a,b)
void insert(int root,int a,int b,int col){
     if(b<tree[root].left||a>tree[root].right)
         return;
     if(a<=tree[root].left && b>=tree[root].right){
         tree[root].cover=col;
         return;
     }
     if(tree[root].cover>=0){
         tree[root*2].cover=tree[root*2+1].cover=tree[root].cover;
         tree[root].cover=-1;
     }
     insert(root*2,a,b,col);
     insert(root*2+1,a,b,col);
} 

void Count(int root,int l,int r){
    if(tree[root].cover>=0) flag[tree[root].cover]=1;
    else if(r-l>=1){
        Count(root*2,l,(l+r)>>1);
        Count(root*2+1,(l+r)>>1+1,r);
    }
}

int main(){
    scanf("%d",&c);
    while(c--){
        memset(dis,0,sizeof(dis));
        memset(flag,0,sizeof(flag));
        scanf("%d",&n);
        int p=0;
        for(i=1;i<=n;i++){
            scanf("%d%d",®[i][0],®[i][1]);
            if(dis[reg[i][0]]==0){
                //设置为访问过,这个过程是为了去重 
                dis[reg[i][0]]=1;
                ep[++p]=reg[i][0];
            }
            if(dis[reg[i][1]]==0){
                dis[reg[i][1]]=1;
                ep[++p]=reg[i][1];
            }
        }
        //离散化 
        sort(ep+1,ep+1+p);
        int hash=0;
        for(i=1;i<=p;i++){
            dis[ep[i]]=++hash;
        }
        //创建线段树 
        build(1,1,p);
        for(i=1;i<=n;i++){
            insert(1,dis[reg[i][0]],dis[reg[i][1]],i);
        }
        Count(1,1,p);
        int res=0;
        for(i=0;i<=n;i++)
            if(flag[i])
                res++;
        if(flag[0])
            printf("%d\n",res-1);
        else
            printf("%d\n",res);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值