POJ 2528 【线段树--离散化,区间覆盖】

这道题想了挺久的。。。。 TAT

听说POJ这道题的数据奇弱,所以有一种常见的离散方法也是可以过得,但是有错。

转:

**********************************************************************

给出下面两个简单的例子应该能体现普通离散化的缺陷:
例子一:1-10 1-4 5-10
例子二:1-10 1-4 6-10
普通离散化后都变成了[1,4][1,2][3,4]
线段2覆盖了[1,2],线段3覆盖了[3,4],那么线段1是否被完全覆盖掉了呢?
例子一是完全被覆盖掉了,而例子二没有被覆盖

为了解决这种缺陷,我们可以在排序后的数组上加些处理,比如说[1,2,6,10]
如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了

**********************************************************************

(⊙v⊙)嗯,是这样的。

然后之前在纠结的时,肯定用cover[rt]=1表示覆盖,cover[rt]=0表示没有覆盖,cover[rt]=cover[rt<<1]&&cover[rt<<1|1],但是这样有个问题啊,就是我在第二次放线段更新的时候。。。就不能表示叠加啦,,根本不能计算数值的嘛!

所以应该这样!

由于贴广告是不断覆盖的过程,所以我们可以这样考虑,如果从最后一个广告开始update,每次判断的就是能不能进行一次有效的update,(这次贴的广告能不能漏出来),那么任务就可以变成找到一个cover[rt]=0的区间覆盖即可。这样省了好多事啊啊!!

然后在离散的时候要注意,由于每个不相邻的数字间要加塞,所以线段树的范围可能会生生扩大一倍,所以注意maxn。

最后,我发现,,楷体比黑体好看噻!

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
#define maxn 20010
int a[maxn<<1];
map<int,int>mapp;
struct node
{
    int l,r;
}que[maxn];
int cover[maxn<<3];
void create(int l,int r,int rt)
{
    cover[rt]=0;
    if(l==r) return;
    int mid=(l+r)>>1;
    create(l,mid,rt<<1);
    create(mid+1,r,rt<<1|1);
}
int update(int ll,int rr,int l,int r,int rt)
{
    if(cover[rt]) return 0;
    if(ll==l&&rr==r)
    {
        cover[rt]=1;
        return 1;
    }
    int mid=(l+r)>>1,ret=0;
    if(rr<=mid) ret=update(ll,rr,l,mid,rt<<1);
    else if(ll>mid) ret=update(ll,rr,mid+1,r,rt<<1|1);
    else
    {
        ret=update(ll,mid,l,mid,rt<<1);
        ret|=update(mid+1,rr,mid+1,r,rt<<1|1);
    }
    if(cover[rt<<1]&&cover[rt<<1|1])
        cover[rt]=1;
    return ret;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n,top=0,ans=0;
        cin>>n;
        for(int i=0;i<n;i++)
        {
            int j,k;
            cin>>j>>k;
            que[i].l=j,que[i].r=k;
            a[top++]=j;a[top++]=k;
        }
        sort(a,a+top);
        int count=unique(a,a+top)-a;
        int ncount=0;
        //create(0,count-1,1);
        for(int i=0,j=0;i<count;i++,j++)
        {
            if(a[i]-1>a[i-1]) j++;
            mapp[a[i]]=j;
            //printf("map[%d]=%d\n",a[i],j);
            ncount=j;
        }
        create(0,ncount,1);
        
        for(int i=n-1;i>=0;i--)
            if(update(mapp[que[i].l],mapp[que[i].r],0,ncount,1))
                ans++;
        cout<<ans<<endl;
        
    }
    return 0;
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值