清華OJ燈塔

題目

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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章