poj 2528 Mayor's posters

思路:线段树加离散化处理。(参考自kuangbin大牛)

首先常规做法  以【8 10】【 3 4】【 7 10】为例,预处理线段树布尔值全为false,从后往前更新,先检查【7,10】区间内是否存在false,存在即返回true,然后此区间全部更新为true,然后依次【3,4】 【8,10】,注意到【8,10】区间内全部为false,返回false。根据体重的数据范围,,这样毫无疑问会MT,所以要离散化处理,即先对所有出现的值排好序,去重, 如

3  4  7  8  10   对应于

1  2  3  4   5  这样范围就大大缩小了

到此为止在poj上用G++提交是可以过的,

但是参阅其他博客,这样的做法是有漏洞的,如 【1,6】 【8,10】【1,10】 这组数据本应是3,但却输出2,究其原因是因为本来不相邻的6,8两点离散化后变成相邻的了,

不理解的话可以在纸上画一下看看,我们这里可以通过在间距大于1的数据中间加一个介于两者之间的数来解决,具体见代码,

另外在poj上提交本体时要用G++,c++的话两种方法都过不去(也可能我姿势还是不太对),如果找出我的错误,欢迎指正


 

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <math.h>
using namespace std;
const int MAXN = 1000100;
struct pp
{
    int l,r;
}p[MAXN*4];
struct note
{
    int l,r;
    bool flag;
}q[MAXN*8];
int _hash[100000005];
int tm[MAXN*4];
void build(int i,int l,int r)
{
    q[i].r=r;
    q[i].l=l;
    q[i].flag=false;
    if(l==r)
        return;
    int m=(l+r)/2;
    build(i*2,l,m);
    build(i*2+1,m+1,r);
}
bool post(int i,int l,int r)
{
    if(q[i].flag)
        return false;
    if(q[i].l==l&&q[i].r==r)
    {
        q[i].flag=true;
        return true;
    }
    bool tmp;
    int m=(q[i].l+q[i].r)/2;
    if(r<=m)
        tmp=post(i*2,l,r);
    else if(l>m)
        tmp=post(i*2+1,l,r);
    else
    {
        bool t1=post(i*2,l,m);
        bool t2=post(i*2+1,m+1,r);
        tmp=t1||t2;  // 这里不能直接取或,要将两个都算出来,否则会因为||运算符的短路原则忽略后面的更新
    }
    if(q[i*2].flag&&q[i*2+1].flag)  //大牛博客中说这里也非常重要。。。
        q[i].flag=true;
    return tmp;

}
int main()
{
   // freopen("in.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        int ncount=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&p[i].l,&p[i].r);
            tm[ncount++]=p[i].l;
            tm[ncount++]=p[i].r;
        }
        sort(tm,tm+ncount);             //排序
        ncount=unique(tm,tm+ncount)-tm;//合并掉相同的项
        int nn=ncount;
        for(int i=1;i<nn;i++)
        {
            if(tm[i]-tm[i-1]>1)
                tm[ncount++]=tm[i]-1;
        }
        sort(tm,tm+ncount);
        for(int i=0;i<ncount;i++)
        {
            _hash[tm[i]]=i+1;
        }
        build(1,1,ncount);

        int ans=0;
        for(int i=n-1;i>=0;i--)           //思路是从后往前贴并检查更新线段树
        {
            if(post(1,_hash[p[i].l],_hash[p[i].r]))
                ans++;
        }
        printf("%d\n",ans);
    }
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值