HDU 2366 Space(二分计数)
Problem Description
During a programming contest, teams cannot sit close to each other, because then a team might copy the solution of another team. You are given the locations of the teams and the minimum required Euclidian distance between two teams. You have to find the number of pairs of teams that sit too close to each other.
Input
On the first line an integer t (1 <= t <= 100): the number of test cases. Then for each test case:
One line with two integers n (1 <= n <= 100 000) and d (1 <= d <= 50): the number of teams and the minimum distance between two teams.
n lines with two integers xi (0 <= xi <= 1 000 000 000) and yi (0 <= yi <= 1 000 000 000): the coordinates of the i-th team. No two teams will have the same coordinates.
One line with two integers n (1 <= n <= 100 000) and d (1 <= d <= 50): the number of teams and the minimum distance between two teams.
n lines with two integers xi (0 <= xi <= 1 000 000 000) and yi (0 <= yi <= 1 000 000 000): the coordinates of the i-th team. No two teams will have the same coordinates.
Output
For each test case:
One line with the number of pairs of teams that sit too close to each other.
One line with the number of pairs of teams that sit too close to each other.
题目大意:给平面上n个点,问有多少对点间的距离小于d。
思路:一眼可以看到,虽然x轴和y轴的范围很大,但是d却很小,这应该是一个突破口。
那么这个d怎么利用呢。思考一下,对于任意一个点P,和它的距离小于d的点,至少应该在一个以P为中心的2d*2d的正方形中。
因为要题目要求的是对数,那么我们可以只考虑P点的右半部分的点(因为左边部分的点与P的组合在计算左边的点的时候已经算了)。
那么,我们就是要考虑,对于点P(x0, y0),只考虑x = x0、x0+1、……、x0+d-1的点。
穷举这些x = x0 + i,那么y轴的范围就应该在[y0 - t, y0 + t]之间,其中 t 是满足i^2 + t^2 < d^2的最大整数(注意题目都是整点)。
如果对于每一个x = x0 + i的点我们都可以收集起来,按y轴排好,那么二分查找,可以得到 结果 = 小于等于y0 + t的数目 - 小于y0 - t的数目。
因为x的范围很大,不可能说每个点开个数组,我们可以用C++的map存起来,每个有可能的x开一个vector,然后排序即可(注意找map中是否存在x的时候最好用map.find(x),直接用map[x]会创建一个x留在map中,可能导致效率的减缓)。
如果不用map也不是不可以,只要把点都从小到大(x轴为第一关键字,y轴第二关键字)排好序,每次需要哪个x的时候二分查找也是可以的。
我们好像还没算x轴相同的呢。对于x轴相同的,弄俩指针,从前往后扫就可以统计出来了,这个还是不难的。
细节可以看代码,时间复杂度为O(n*d*log(n))。
代码(14109MS):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <iostream> 5 #include <map> 6 #include <vector> 7 using namespace std; 8 typedef long long LL; 9 10 const int MAXN = 100010; 11 12 int T, n, d, x, y; 13 map<int, vector<int> > mymap; 14 15 LL solve() { 16 LL ans = 0; 17 for(map<int, vector<int> >::iterator it = mymap.begin(); it != mymap.end(); ++it) { 18 sort(it->second.begin(), it->second.end()); 19 for(int i = 0, j = 0, n = it->second.size(); i < n; ++i) { 20 while(j < n && it->second[i] + d > it->second[j]) ++j; 21 ans += j - i - 1; 22 } 23 } 24 int d2 = d * d; 25 for(map<int, vector<int> >::iterator it = mymap.begin(); it != mymap.end(); ++it) { 26 for(vector<int>::iterator p = it->second.begin(); p != it->second.end(); ++p) { 27 for(int i = 1, t = d; i < d; ++i) { 28 while(i * i + t * t >= d2) --t; 29 map<int, vector<int> >::iterator nx = mymap.find(it->first + i); 30 if(nx != mymap.end()) { 31 ans += (upper_bound(nx->second.begin(), nx->second.end(), *p + t) - nx->second.begin()) - 32 (lower_bound(nx->second.begin(), nx->second.end(), *p - t) - nx->second.begin()); 33 } 34 } 35 } 36 } 37 return ans; 38 } 39 40 int main() { 41 scanf("%d", &T); 42 while(T--) { 43 mymap.clear(); 44 scanf("%d%d", &n, &d); 45 for(int i = 0; i < n; ++i) { 46 scanf("%d%d", &x, &y); 47 mymap[x].push_back(y); 48 } 49 printf("%I64d\n", solve()); 50 } 51 }