Tsinghua mooc 数据结构上 灯塔(LightHouse) 归并排序

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

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

若灯塔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],不一定足够容纳本题的输出。

上代码:

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

简单说就是横纵坐标都小于另外一个位置就满足条件。接下来就懵逼了,直接比较时间复杂度O(n)过不了,可是要排序怎么排呢?
去网上搜了下才发现了归并排序,都怪我看视频不认真,现在都忘了(emmm又去补了一遍),算法思想类似也是分而治之,将原数组划分开,再按大小顺序将小的元素逐渐排列成有序数组,在这个过程中可以找出数组中逆序对(例如:i<j; a[i]>a[j]; ),或者顺序对的个数。
解题方法就是先按x排序(快排),再按y的大小找出有多少顺序对。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值