51Nod_1278 相离的圆
http://www.51nod.com/Challenge/Problem.html#!#problemId=1278
题目
平面上有N个圆,他们的圆心都在X轴上,给出所有圆的圆心和半径,求有多少对圆是相离的。例如:4个圆分别位于1, 2, 3, 4的位置,半径分别为1, 1, 2, 1,那么{1, 2}, {1, 3} {2, 3} {2, 4} {3, 4}这5对都有交点,只有{1, 4}是相离的。
输入
第1行:一个数N,表示圆的数量(1 <= N <= 50000);第2 - N + 1行:每行2个数P, R中间用空格分隔,P表示圆心的位置,R表示圆的半径(1 <= P, R <= 10^9)
输出
输出共有多少对相离的圆。
样例输入
4
1 1
2 1
3 2
4 1
样例输出
1
分析
将圆看作一条在X轴上的线段,左右端点的坐标为圆心坐标减、加半径。然后将线段进行排序,左端点小的排在前面,左端点相同时右端点小的排在前面 ,然后遍历n个圆,统计与此时遍历的圆相离的圆的个数,找到第一个与圆i相离的圆的编号,由排序原则可知,此圆之后的圆都与圆i相离,使用二分法查找与圆i相离的第一个圆的编号,具体看程序。
C++程序
#include<iostream>
#include<algorithm>
using namespace std;
const int N=50100;
typedef long long ll;
struct Line{
int l,r;//左右端点的一维坐标
bool operator <(const Line &p)const
{
//左端点小的排在前面,左端点相同时右端点小的排在前面
return l==p.l?(r<p.r):(l<p.l);
}
}a[N];
int main()
{
int n,x,r;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d%d",&x,&r);
a[i].l=x-r;
a[i].r=x+r;
}
sort(a,a+n);
ll ans=0;
for(int i=0;i<n;i++)//统计与圆i相离的圆的个数
{
//找到第一个与圆i相离(a[id].l>a[i].r)的圆的编号,由排序原则可知,此圆之后的圆都与圆i相离
//使用二分查找
int l=i+1,r=n-1,mid=n;
while(l<=r)
{
mid=(l+r)/2;
if(a[mid].l<a[i].r)
l=mid+1;
else if(a[mid].l>a[i].r)
r=mid-1;
else
break;
}
while(mid<n&&a[mid].l<=a[i].r) mid++; //记录第一个与圆i相离的圆的编号
if(mid!=n)
ans+=n-mid;
}
printf("%lld\n",ans);
return 0;
}