线段树 离散化 poj2528

题意 n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000)。

      求出最后还能看见多少张海报。

如输入 离散化只要记录1 4 2 6 8 10 7 3

排序后为 1 2  3 4 6 7 8 10

1 2 3 4 5 6 7  8

然后输入

1 4

1~4=1  1

2 6

1=1 2~5=2   2

8 10 

1=1 2~5=2 7~8=3  3

3  4

1=1 2=2  3~4=4 5=2 7~8=3  4

7 10

1=1 2=2  3~4=4 5=2 6~8=5  4

然后看有几种不同颜色

但是当输入

 3

1 8

1 4 

6 8

时比较特殊

1 4 6 8

1 2 3 4

1~4=1   1

1~2=2 3~4=1   2

1~2=2 3~4=3  2

而实际上为3

所以

可以  在相差大于一的中间加上一个数

变成 1 3 4 5 6 7 8

就可以了

Sample Input

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

Sample Output

4
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<stack>
using namespace std;
#define ll long long
#define cl(a,b) memset(a,b,sizeof(a))
#define N 50005
#define MAXN 10005
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
int sum[MAXN<<4],n,a[MAXN<<3];
int li[MAXN],ri[MAXN];
int f[MAXN];
int ans;
/*void push_up(int i)//是把当前结点的信息更新到父结点
{
    sum[i]=min(sum[i<<1],sum[i<<1|1]);
}*/
void push_down(int i)//是把当前结点的信息更新给儿子结点
{
     sum[i<<1]=sum[i<<1|1]=sum[i];
     sum[i]=-1;
}
/*void build(int L,int R,int i,int l,int r)
{
    sum[i]=r-l+1;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(L,R,lson);
    build(L,R,rson);
}*/
void update(int L,int R,int c,int i,int l,int r)
{
    if(l>=L&&r<=R)
    {
        sum[i]=c;
        return;
    }
    if(sum[i]!=-1)push_down(i);
    int mid=(l+r)>>1;
    if(L<=mid)update(L,R,c,lson);
    if(R>mid)update(L,R,c,rson);

}
void query(int i,int l,int r)
{
    if(sum[i]!=-1)
    {
        if(!f[sum[i]]){
            f[sum[i]]=1;
            ans++;
        }
        return;
    }
    if(l==r)return;
    int mid=(l+r)>>1;
    query(lson);
    query(rson);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        int m=0;
        cl(sum,-1);
        cl(f,0);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&li[i],&ri[i]);
            a[++m]=li[i];
            a[++m]=ri[i];
        }
        sort(a+1,a+m+1);
        int j=1;
        for(int i=2;i<=m;i++)
            if(a[i]!=a[i-1])a[++j]=a[i];
        for(int i=j;i>=2;i--)
            if(a[i]-a[i-1]>1)a[++j]=a[i]-1;
        sort(a+1,a+j+1);
        for(int i=1;i<=n;i++)
        {
            int l=lower_bound(a+1,a+j+2,li[i])-a;
            int r=lower_bound(a+1,a+j+2,ri[i])-a;
            update(l,r,i,1,1,j);
        }
        ans=0;
        query(1,1,j);
        printf("%d\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值