描述
海上有许多灯塔,为过路船只照明。
每个灯塔都配有一盏探照灯,照亮其东北、西南两个对顶的直角区域。探照灯的功率之大,足以覆盖任何距离。灯塔本身是如此之小,可以假定它们不会彼此遮挡。
若灯塔A、B均在对方的照亮范围内,则称它们能够照亮彼此。
现在,对于任何一组给定的灯塔,请计算出其中有多少对灯塔能够照亮彼此。
输入
共n+1行。
第1行为1个整数n,表示灯塔的总数。
第2到n+1行每行包含2个整数x, y,分别表示各灯塔的横、纵坐标。
输出
1个整数,表示可照亮彼此的灯塔对的数量。
样例
Input
3
2 2
4 3
5 1
Output
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],不一定足够容纳本题的输出。
简单说就是横纵坐标都小于另外一个位置就满足条件。接下来就懵逼了,直接比较时间复杂度O(n)过不了,可是要排序怎么排呢?
去网上搜了下才发现了归并排序,都怪我看视频不认真,现在都忘了(emmm又去补了一遍),算法思想类似也是分而治之,将原数组划分开,再按大小顺序将小的元素逐渐排列成有序数组,在这个过程中可以找出数组中逆序对(例如:i
#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=4e6+10;
struct node
{
int x;
int y;
void operator = (const node &a)
{
x = a.x;
y = a.y;
}
};
long long int num = 0;
long src[maxn];
long des[maxn];
node total[maxn];
void quickSort(int l,int r)
{
if(l < r)
{
int i = l, j = r;
node n1 = total[i];
int key = n1.x;
while(i < j)
{
while(i < j && key <= total[j].x)
j--;
if(i < j)total[i++] = total[j];
while(i < j && total[i].x < key)
i++;
if(i < j)total[j--] = total[i];
}
total[i] = n1;
quickSort(l, i);
quickSort(i+1, r);
}
}
void merge(int l, int mid, int r)
{
int i = l, j = mid + 1;
int k = l;
while(i != mid + 1 && j != r + 1)
{
if(src[i] < src[j])
{
des[k++] = src[i++];
num += r - j + 1; //找出顺序对的数目
}
else des[k++] = src[j++];
}
while(i != mid + 1)des[k++] = src[i++];
while(j != r + 1)des[k++] = src[j++];
for(i = l; i != r+1; i++)
src[i] = des[i];
}
void mergesort(int l, int r) //划分为小的单元再归并
{
int mid;
if(l < r)
{
mid = (l + r) >> 1;
mergesort(l, mid);
mergesort(mid+1, r);
merge(l, mid, r);
}
}
int main()
{
int n;
scanf( "%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%d%d", &total[i].x, &total[i].y);
}
quickSort(0, n-1);
for(int i = 0; i < n; i++)
{
src[i] = total[i].y;
}
num = 0;
mergesort(0, n-1);
printf("%lld\n",num);
return 0;
}