poj2528(线段树+离散化)

对于区间特别大的  (1~1e7)

但是覆盖次数又特别小的

我们采用离散化..


如样列:

1 4

2 6

8 10

3 4

7 10


把每对拆开  升序排序  去重  得:

1  2  3  4  6  7  8 10

对应序号

1  2  3  4  5  6  7  8

把区间关系用序号的关系来替代:

1  4

2  5

7  8

3  4

6  8

这样  区间是不是就被压缩了呢?


标记:

每个节点有三种值  >0  ==-1  ==0

==0:未被染色     >0:染单色    ==-1:染复色

更新时   不包含:结束   完全包含:直接染色      >=0   改节点为-1并将原色向下推 


询问时     遇到==0返回      >0  记录  返回,  



#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#define gl l,(l+r)>>1,num<<1
#define gr ((l+r)>>1)+1,r,num<<1|1
const int MAXN = 20005;

using namespace std;
int pa[10005][2],save[MAXN];
short dis[10000005];
bool tag[10005];

short st[10005<<4];
void insert(int v,int a,int b,int l,int r,int num)
{
    if(b<l||a>r)
        return;
    if(a<=l&&b>=r)
    {
        st[num]=v;
        return;
    }
    if(st[num]>=0)
    {
        st[num<<1]=st[num];
        st[num<<1|1]=st[num];
        st[num]=-1;
    }
    insert(v,a,b,gl);
    insert(v,a,b,gr);
}

int cnt=0;
void calc(int l,int r,int num)
{
    if(!st[num])return;
    if(st[num]>0)
    {
        if(!tag[st[num]]) cnt++,tag[st[num]]=1;
        return;
    }
    calc(gl);
    calc(gr);
}

int main()
{
    //freopen("a.in","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        memset(dis,0,sizeof(dis));
        memset(st,0,sizeof(st));
        int num=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&pa[i][0],&pa[i][1]);
            if(!dis[pa[i][0]])
                save[num++]=pa[i][0];
            if(!dis[pa[i][1]])
                save[num++]=pa[i][1];
            dis[pa[i][0]]++;
            dis[pa[i][1]]++;
        }
        sort(save,save+num);
        int hash=0;
        for(int i=0;i<num;i++)
            dis[save[i]]=(++hash);
        for(int i=0;i<n;i++)
        {

            pa[i][0]=dis[pa[i][0]];
            pa[i][1]=dis[pa[i][1]];
            insert(i+1,pa[i][0],pa[i][1],1,hash,1);
        }
        cnt=0;
        memset(tag,0,sizeof(tag));
        calc(1,hash,1);
        printf("%d\n",cnt);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值