POJ2528Mayor's posters

题目大意:

就跟在电线杆上帖小广告一样,先贴的总是会被后帖的给覆盖了,现在要求你求出当最后一张小广告贴上去之后还剩多少没有被完全覆盖。

解题思路:

        这个思路还是线段树的思路,但是由于数据范围太大了,所以要做离散化处理,要用到的其实就是一些个左端点啊,右端点,以及为了防止漏掉中间断层而添加的中间的点。

具体思路看代码:

#include<stdio.h>
#include<set>
#include<string.h>
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define N 20009
using namespace std;
int st[N<<2],ed[N<<2];//保存端点的
int temp[N<<2];//离散化的点
set<int>sett;//中间处理的时候用
bool visit[N<<2],use[N<<3];//标记
void build(int rt,int l,int r)//建树也就是清空,可以用memset取而代之
{
    use[rt]=false;
    if(l==r)
        return ;
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
}
int ans=0;

void update(int rt,int l,int r,int a,int b,int c)//查找并更新
{
    if(use[rt])
        return ;
    if(temp[l]>=a&&temp[r]<=b)
    {
            use[rt]=true;
            if(!visit[c])
            {
                ans++;
                visit[c]=true;
            }
            return ;
    }
    int mid=(l+r)>>1;
    if(b<=temp[mid])
       update(lson,a,b,c);
    else if(a>temp[mid])
        update(rson,a,b,c);
    else
    {
        update(lson,a,temp[mid],c);//向左边缩小范围
        update(rson,temp[mid+1],b,c);//。。。
    }
    if(use[rt<<1]&&use[rt<<1|1])
        use[rt]=true;
}
int main()
{
    int t;
    scanf("%d",&t);
    int n,i,a,b,nn;
    while(t--)
    {
        sett.clear();
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
             scanf("%d%d",&st[i],&ed[i]);
        }
        sett.insert(st,st+n);
        sett.insert(ed,ed+n);
        set<int>::const_iterator ir,jr;
        jr=sett.begin();
        jr++;
        i=0;
        for(ir=sett.begin();jr!=sett.end();ir++,jr++)
        {
            if(*ir+1!=*jr)
                temp[i++]=*ir+1;
        }
        sett.insert(temp,temp+i);
           i=0;
        for(ir=sett.begin();ir!=sett.end();ir++)
            temp[++i]=*ir;
        nn=i;
        build(1,1,nn);
        memset(visit,false,sizeof(visit));
        ans=0;
        for(i=n-1;i>=0;i--)
        {
            update(1,1,nn,st[i],ed[i],i);
        }
        printf("%d\n",ans);
    }
}
这个时间复杂度有点大。。。待优化。

继续。。。。

去掉Set和memset,从500多优化到63,内存从2000多优化到779,恩,看来STL库不能随便用啊。。。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define N 20009
using namespace std;
int st[N<<2],ed[N<<2];
int temp[N<<3];
bool visit[10000009],use[N<<3];
void build(int rt,int l,int r)
{
    use[rt]=false;
    if(l==r)
        return ;
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
}
int ans=0;
void update(int rt,int l,int r,int a,int b,int c)
{
    if(use[rt])
        return ;
    if(temp[l]>=a&&temp[r]<=b)
    {
            use[rt]=true;
            if(!visit[c])
            {
                ans++;
                visit[c]=true;
            }
            return ;
    }
    int mid=(l+r)>>1;
    if(b<=temp[mid])
       update(lson,a,b,c);
    else if(a>temp[mid])
        update(rson,a,b,c);
    else
    {
        update(lson,a,temp[mid],c);
        update(rson,temp[mid+1],b,c);
    }
    if(use[rt<<1]&&use[rt<<1|1])
        use[rt]=true;
}
int main()
{
    int t;
    scanf("%d",&t);
    int n,i,nn,j;
    while(t--)
    {
        scanf("%d",&n);
        j=0;
        for(i=0;i<n;i++)
        {
             scanf("%d%d",&st[i],&ed[i]);
                temp[j++]=st[i];
                temp[j++]=ed[i];
        }
        nn=j;
        sort(temp,temp+nn);
        for(i=0,j=0;j<nn;j++){
            if(temp[i]!=temp[j+1])
               temp[++i]=temp[j+1];
        }
        nn=i+1;
        for(i=nn-2,j=nn-1;i>=0;i--,j--)
        {
            if(temp[i]+1!=temp[j])
                 temp[nn++]=temp[i]+1;
        }
        temp[nn]=0;
        sort(temp,temp+nn+1);
        build(1,1,nn);
        for(i=0;i<n;i++)
           visit[i]=false;
        ans=0;
        for(i=n-1;i>=0;i--)
        {
            update(1,1,nn,st[i],ed[i],i);
        }
        printf("%d\n",ans);
    }
}

end...

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值