POJ T2528 Mayor's posters 题解(线段树和离散化)

题目链接

题目大意

其实就不是不停的张贴海报,可能后面的海报可以把前面的海报覆盖,求最后能看到多少张海报(只要没有被全部覆盖就算可以看见)

题目思路

此题是线段树区间覆盖问题,显然数据过大,故要离散化。还有此题根本没有必要进行建树的操作,最开始都是0。

易错警示

1:此题有一个坑点。如 1,10 1,4 7,10 这三组数的正确结果应该是还以看到3种颜色,但是如果直接排列点的话就会挤掉5到6这一

种颜色。所以离散的时候可以离散a,a+1,a-1,b,b-1,b+1就不会出现这种情况。

2:本题我多次re,故再次总结re的常见原因。数组越界,多次递归爆栈,除0模0会造成re,而我是询问的时候只询问了一半的区间

而可能那半边区间正好没有return的结果就会一直递归,然后到最后才截至。

3:数组大小不只是4e5,因为有a,b两个数组,故应该最少是8e5,但是离散所要用的数组又是6e5,开大一点没错

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=24e5+5;
int t,n,i,j=1,temp[maxn],vis[maxn],ans,a[maxn],b[maxn],tree[maxn];
void updown(int node)//相当于把自己当作懒标记
{
        tree[node<<1]=tree[node<<1|1]=tree[node];
        tree[node]=0;
        return ;
}
void update(int node,int l,int r,int L,int R,int k)//小写l,r是要修改的范围,大写L,R是node的范围
{
    if(l<=L&&r>=R)
    {
        tree[node]=k;
        return ;
    }
    if(tree[node])
    updown(node);//懒标记
    int mid=(L+R)>>1;
    if(mid>=l) update(node<<1,l,r,L,mid,k);
    if(mid<r)  update(node<<1|1,l,r,mid+1,R,k);
    return ;
}
void query(int node,int l,int r)
{
    if(l==r&&tree[node]==0)
    {
        return ;
    }
    if(tree[node])
    {
        vis[tree[node]]=1;
        return ;
    }
    int  mid=(l+r)/2;
    query(node<<1,l,mid);
    query(node<<1|1,mid+1,r);
    return ;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        memset(tree,0,sizeof(tree));//清零
        memset(vis,0,sizeof(vis));
        j=1;
        ans=0;
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%d %d",&a[i],&b[i]);
            temp[j++]=a[i];//离散要用的数组
            temp[j++]=b[i];
            temp[j++]=a[i]-1;
            temp[j++]=a[i]-1;
            temp[j++]=b[i]+1;
            temp[j++]=b[i]+1;
        }
        sort(temp+1,temp+1+6*n);//为离散做准备
        int cnt=unique(temp+1,temp+1+6*n)-temp-1;//找出不重复的数的个数
        for(i=1;i<=n;i++)//离散化
        {
            a[i]=lower_bound(temp+1,temp+1+cnt,a[i])-temp;
            b[i]=lower_bound(temp+1,temp+1+cnt,b[i])-temp;
            update(1,a[i],b[i],1,6*n+1,i);//更新线段树,最后一个参数表示染的颜色
        }
        query(1,1,6*n+1);//询问
        for(i=1;i<=6*n+1;i++)
        {
            if(vis[i]) ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

如有错误,欢迎指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值