題目
Description
As shown in the following figure, If another lighthouse is in gray area, they can beacon each other.
For example, in following figure, (B, R) is a pair of lighthouse which can beacon each other, while (B, G), (R, G) are NOT.
Input
1st line: N
2nd ~ (N + 1)th line: each line is X Y, means a lighthouse is on the point (X, Y).
Output
How many pairs of lighthourses can beacon each other
( For every lighthouses, X coordinates won’t be the same , Y coordinates won’t be the same )
Example
Input
3
2 2
4 3
5 1
Output
1
Restrictions
For 90% test cases: 1 <= n <= 3 * 105
For 95% test cases: 1 <= n <= 106
For all test cases: 1 <= n <= 4 * 106
For every lighthouses, X coordinates won’t be the same , Y coordinates won’t be the same.
1 <= x, y <= 10^8
Time: 2 sec
Memory: 256 MB
Hints
The range of int is usually [-231, 231 - 1], it may be too small.
描述
海上有許多燈塔,爲過路船隻照明。
(圖一)
如圖一所示,每個燈塔都配有一盞探照燈,照亮其東北、西南兩個對頂的直角區域。探照燈的功率之大,足以覆蓋任何距離。燈塔本身是如此之小,可以假定它們不會彼此遮擋。
(圖二)
若燈塔A、B均在對方的照亮範圍內,則稱它們能夠照亮彼此。比如在圖二的實例中,藍、紅燈塔可照亮彼此,藍、綠燈塔則不是,紅、綠燈塔也不是。
現在,對於任何一組給定的燈塔,請計算出其中有多少對燈塔能夠照亮彼此。
輸入
共n+1行。
第1行爲1個整數n,表示燈塔的總數。
第2到n+1行每行包含2個整數x, y,分別表示各燈塔的橫、縱座標。
輸出
1個整數,表示可照亮彼此的燈塔對的數量。
樣例
見英文題面
限制
對於90%的測例:1 ≤ n ≤ 3×105
對於95%的測例:1 ≤ n ≤ 106
全部測例:1 ≤ n ≤ 4×106
燈塔的座標x, y是整數,且不同燈塔的x, y座標均互異
1 ≤ x, y ≤ 10^8
時間:2 sec
內存:256 MB
提示
注意機器中整型變量的範圍,C/C++中的int類型通常被編譯成32位整數,其範圍爲[-231, 231 - 1],不一定足夠容納本題的輸出。
分析
A和B能夠相互照亮的條件(假設A(x)<B(x))就是B在A的右上方。注意原題註明了:不同燈塔的x, y座標均互異。 所以只要我們首先將所有點按照x座標排序,接下來在y座標中統計所有“非逆序對”,再求和,就可以了。
而問題的關鍵就在於在這樣的數據規模下如何快速的統計出“順序對”的個數。 如果只是單純的O(n^2)的算法顯然是效率不夠的。 那,如何從向量中快速的統計出“順序對”的個數? 這裏大概思考之後可以聯想到 歸併排序。
歸併排序的關鍵也就是用分治的策略,將原問題一分爲二的遞歸下去,最後的關鍵步驟只是將左右兩個有序的區間合併起來即可。 而很快會發現,在合併的過程中似乎我們就可以順便統計“順序對”的個數。
考慮這樣的一種情形: 目前左右兩個有序區間,分別有指針 i, j 指向該區間下一個要合併的元素。 當a[i] < a[j]的時候(不可能相等,原題目已經說明),此時 a[i] 就要被合併。 而 a[j]以及所有右區間大於 a[j] 的元素 其實都與 a[i] 構成“順序對”。 統計完後,i 指向 i++的元素,且區間也都是沒有重疊部分的,所以也並不會重複計數。 這樣在歸併排序合併的同時,也將所有的“順序對”無重複無遺漏地記錄了下來。
算法複雜度也就是O(nlogn)的。
我的代碼:
#include <stdio.h>
#define MAXN 4000010
struct Point
{
long x;
long y;
}points[MAXN];
long count;
long src[MAXN];
long des[MAXN];
void qsort(Point ps[], int l, int r)
{
if (l < r)
{
int i = l, j = r;
Point tmp;
tmp.x = ps[i].x;
tmp.y = ps[i].y;
int key = ps[i].x;
while (i < j)
{
while (i < j && key < ps[j].x) --j;
ps[i].x = ps[j].x;
ps[i].y = ps[j].y;
while (i < j && ps[i].x < key) ++i;
ps[j].x = ps[i].x;
ps[j].y = ps[i].y;
}
ps[i].x = tmp.x;
ps[i].y = tmp.y;
qsort(ps, l, i - 1);
qsort(ps, i + 1, r);
}
}
void merge(long *src, long *des, int start, int mid, int end)
{
int i = start, j = mid + 1;
int k = start;
while (i != mid + 1 && j != end + 1)
{
if (src[i] < src[j])
{
des[k++] = src[i++];
count += end - j + 1;
}
else des[k++] = src[j++];
}
while (i != mid + 1) des[k++] = src[i++];
while (j != end + 1) des[k++] = src[j++];
for (i = start; i != end + 1; ++i)
src[i] = des[i];
}
void mergeSort(long *src, long *des, int start, int end)
{
int mid;
if (start < end)
{
mid = (start + end) >> 1;
mergeSort(src, des, start, mid);
mergeSort(src, des, mid + 1, end);
merge(src, des, start, mid, end);
}
}
int main()
{
int n;
int i;
scanf("%d", &n);
for (i = 0; i < n; ++i)
scanf("%ld %ld", &points[i].x, &points[i].y);
qsort(points, 0, n - 1);
for (i = 0; i < n; ++i)
src[i] = points[i].y;
count = 0;
mergeSort(src, des, 0, n - 1);
printf("%ld\n", count);
return 0;
}