質問 3 灯台 (LightHouse)

海上には灯台がたくさんあり、行き交う船を照らします。

(図1)
図1に示すように、各灯台には北東側と南西側の2つの直角エリアを照らすサーチライトが装備されています。サーチライトはあらゆる距離をカバーできるほど強力です。灯台自体は非常に小さいので、お互いを遮ることはないと考えられます。

(図2)
灯台Aと灯台Bがお互いの照射範囲内にある場合、相互に照射できると言われています。たとえば、図 2 の例では、青と赤の灯台は相互に照明できますが、青と緑の灯台は相互に照明できず、赤と緑の灯台も互いに照明できません。
ここで、特定の灯台のセットについて、何組の灯台が相互に照明できるかを計算します。

入力形式:
合計 n+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
コード:

//本题的逻辑结构:线性
//本题的存储结构:顺序结构
//解题思路和算法:升序快排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