第3题 灯塔(LightHouse)

海上有许多灯塔,为过路船只照明。

(图一)
如图一所示,每个灯塔都配有一盏探照灯,照亮其东北、西南两个对顶的直角区域。探照灯的功率之大,足以覆盖任何距离。灯塔本身是如此之小,可以假定它们不会彼此遮挡。

(图二)
若灯塔A、B均在对方的照亮范围内,则称它们能够照亮彼此。比如在图二的实例中,蓝、红灯塔可照亮彼此,蓝、绿灯塔则不是,红、绿灯塔也不是。
现在,对于任何一组给定的灯塔,请计算出其中有多少对灯塔能够照亮彼此。

输入格式:
共n+1行。
第1行为1个整数n,表示灯塔的总数。
第2到n+1行每行包含2个整数x, y,分别表示各灯塔的横、纵坐标。

要求:
1 ≤ n ≤ 4×10^6
灯塔的坐标x, y是整数,且不同灯塔的x, y坐标均互异
1 ≤ x, y ≤ 10^8

输出格式:
1个整数,表示可照亮彼此的灯塔对的数量。

输入样例:
3
2 2
4 3
5 1
输出样例:
在这里给出相应的输出。例如:

1
code:

//本题的逻辑结构:线性
//本题的存储结构:顺序结构
//解题思路和算法:升序快排x坐标,升序归并排序y坐标并求逆序对,答案等于n*(n-1)/2-逆序对数
//效率:时间复杂度O(nlogn)、空间复杂度O(n)
//测试数据:
/*
(1)
输入:
3
2 2
4 3
5 1


输出:
1

*/
#include <bits/stdc++.h>
#define rep(i,a,b) for(auto i=(a);i<=(b);i++)
#define dep(i,a,b) for(auto i=(a);i>=(b);--i)

using namespace std;
typedef long long ll;
const int N = 4e6+10;

ll n;
struct node {
    
       /* 灯塔结构体,存x和y坐标 */
    int x,y;
}s[N];

int y[N];       /* 单独存y坐标,用来归并排序 */
int temp[N];     /* 存排序好的y坐标 */
ll cnt;         /* 排序前y坐标逆序对数量 */

void MergeArray(int left,int mid,int right);    /* 归并排序数组赋值,将当前区间已排序元素复制到temp数组中 */
void MergeSort(int left,int right);             /* 归并排序 */


void AC(){
    
    
    scanf("%lld",&n);
    rep(i,1,n){
    
    
        scanf("%d %d",&s[i].x,&s[i].y);
    }
    
    sort(s+1,s+1+n,[&](node a,node b){
    
    return a.x<b.x;}); /* 利用匿名结构体排序函数对灯塔按x坐标升序排序 */
    
    rep(i,1,n){
    
    
        y[i] = s[i].y;      /* 将y坐标另外存到数组中便于归并排序 */
    }
    
    MergeSort(1,n);         /* 对y进行归并排序并统计逆序对数量 */
    
    printf("%lld\n",n*(n-1)/2-cnt); /* 答案等于次序总数减去逆序对个数(即顺序对个数 */
}


int main(){
    
    
    int _ = 1;/* 样例组数 */
    //scanf("%d",&_);
    while(_--){
    
    
        AC();
    }
    return 0;
}

void MergeSort(int left,int right){
    
     /* 归并排序 */
    if(left >= right)return;
    int mid = (left+right)>>1;
    
    MergeSort(left,mid);            /* 排序左半部分 */
    MergeSort(mid+1,right);         /* 排序右半部分 */
    
    MergeArray(left,mid,right);     /* 将当前区间已排序元素复制到temp数组中 */
}

void MergeArray(int left,int mid,int right){
    
     /* 将当前区间已排序元素复制到temp数组中 */
    int tot = 0;        /* temp数组指针 */
	int t1 = left;      /* 区间左半部分指针 */
    int t2 = mid + 1;   /* 区间右半部分指针 */
    
	while(t1 <= mid && t2 <= right){
    
        /* 当任意一部分未遍历完 */
		if(y[t1] < y[t2]) {
    
                 /* 左半部分当前元素小 */
            temp[++tot] = y[t1++];      
        }
		else {
    
                              /* 右半部分当前元素小 */
			temp[++tot] = y[t2++];
			cnt += mid-t1+1;            /* 统计逆序对数量 */
		}
	}
    
	while(t1 <= mid) {
    
              /* 遍历左半部分剩下元素 */
        temp[++tot] = y[t1++]; 
    }
	while(t2 <= right) {
    
            /* 遍历右半部分剩下元素 */
        temp[++tot] = y[t2++];
    }
    
	rep(i,left,right) {
    
             /* 将已排序好的元素复制到y数组中 */
	    y[i] = temp[i-left+1];
    }
}

猜你喜欢

转载自blog.csdn.net/qq_51152918/article/details/126687792