Cover
cover.cpp/pas/c/1s/256M
【题目描述】
有 N 个时间段,某个时间段可能包含其它时间段。
请找出能包含其它时间段最多的那个段,并计算出它包括的其它时间段有多少?
【数据范围】
1 <= N <= 25,000
1 <= 时间段开始和结束点 <= 2,000,000,000
【输入文件】
文件名:cover.in
第1行:一个整数 N
第2..N+1行:第i+1行有两个整数A,B(1 <= A < B <= 2,000,000,000)表示第 i个时间段的开始和结束端点。任意两个时间段的端点不相同。
【输出文件】
文件名:cover.out
一行,一个整数。表示一段最多可包含的时间段数的最大值。
样例
输入 | 4
| *-----------*
|
输出 | 2 | 第1段包含2,3两段 |
先说说O(N2)常规方法,很好写,一个二重循环,然后判断 l 和 r 即可
但是看看范围,显然不能在规定时间内出解
这一题可以用单调队列来做,不过这里说另一种方法
如果做过 星星POJ2352 那道题的话,这应该会有点似曾相识的感觉
我们可以按照 r 进行排序,保证前面线段的R肯定是在当前线段R的左边,那么我们就只需要看前面那个线段的L是不是在当前线段的 [ L , R ] 这个区间内就可以知道当前线段是否包含前面那个线段!
这样就可以按照那道题的方法(那道题的题目是排好了序的),扫描一次,每次查找线段树(附加信息是维护的线段的左端点)内有几个是在当前区间内,再插入当前线段左端点即可
但是我们看看数据范围,N≤25000,但是端点的坐标是在 [ 1 , 2000000000 ] 这个区间内的,显然线段树是开不下的!但是我们发现N远远小于这个范围,并且题目说了任意两个端点不同,所以我们可以离散化!将 [ 1 , 2000000000 ] 这个区间内的数排个序,然后依次标号1...N*2,这样我们就可轻松的 A 了
不过离散化我不是怎么会写,所以就暴力了一下,用了一下map,所以有几组时间会有一点点久~~
C++ Code
/*
C++ Code
http://blog.csdn.net/jiangzh7
By Jiangzh
*/
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
const int MAXN=25000+10;
int n;
struct node{int l,r;}a[MAXN];
int newa[MAXN*2],cnt=0;
map<int,int> list;
int sum[MAXN*2*4];
void read()
{
freopen("cover.in","r",stdin);
freopen("cover.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].l,&a[i].r);
newa[cnt++]=a[i].l; newa[cnt++]=a[i].r;
}
}
bool cmp(node a,node b)
{
if(a.r==b.r) return a.l>b.l;
return a.r<b.r;
}
void add_tree(int p,int l,int r,int a)
{
if(l==r && l==a){sum[p]++;return;}
int m=(l+r)>>1;
if(a<=m) add_tree(p<<1,l,m,a);
if(a>m) add_tree((p<<1)+1,m+1,r,a);
sum[p]++;
}
int count(int p,int l,int r,int a,int b)
{
if(a<=l&&b>=r) return sum[p];
int m=(l+r)>>1,x1=0,x2=0;
if(a<=m) x1=count(p<<1,l,m,a,b);
if(b>m) x2=count((p<<1)+1,m+1,r,a,b);
return x1+x2;
}
void predoing()
{
sort(newa,newa+cnt);
for(int i=0;i<cnt;i++) list[newa[i]]=i;
for(int i=1;i<=n;i++)
{
a[i].l=list[a[i].l];
a[i].r=list[a[i].r];
}
//for(int i=1;i<=n;i++) printf("%d %d\n",a[i].l,a[i].r);
}
void work()
{
predoing();//离散化
sort(a+1,a+1+n,cmp);
int ans=0;
for(int i=1;i<=n;i++)
{
int cnt=count(1,0,n*2,a[i].l,a[i].r);
ans=max(ans,cnt);
add_tree(1,0,n*2,a[i].l);
}
printf("%d",ans);
}
int main()
{
read();
work();
return 0;
}