思路:线段树加离散化处理。(参考自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);
}
}