归并排序

运用了分治的思想,将一个数组分成几乎相等的两份,分别将两段中第一个最小的数拿出来放在一个临时数组中,直到全部取完。因为是递归的,所以每一段的数列都是排序好的。

复制代码
void merge_sort(ll *A,ll *B,int x,int y)
{
    if(y-x<=1)return;
    int m=x+(y-x>>1);
    int p=x,q=m,i=x;
    merge_sort(A,B,x,m);
    merge_sort(A,B,m,y);
    while(p<m or q<y)
    {
        if(q>=y or (p<m and A[p]<=A[q]))B[i++]=A[p++];
        else B[i++]=A[q++];
    }
    for(int i=x;i<y;i++)A[i]=B[i];
}
复制代码

(没验证,有错误请指出)

这段代码中左端为闭,右端为开。因此调用时要将右端点+1

O(nlogn)

它有一个神奇的应用:求逆序对(的和)!因为我们发现每次递归时左边的还没有入列的数都是大于右边的数的,所以我们只要在else句的后面加上ans+=m-p就好辣!

洛谷P1908

复制代码
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
template <typename T>
inline T read()
{
    int w=0;T x=0;char c=getchar();
    while(!isdigit(c))w|=c=='-',c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return w?-x:x;
}
const int maxn=5e5+10;
int n;
ll A[maxn],B[maxn],ans;

void merge_sort(ll *A,ll *B,int x,int y)
{
    if(y-x<=1)return;
    int mid=x+(y-x)/2;
    int p=x,q=mid,i=x;
    merge_sort(A,B,x,mid);
    merge_sort(A,B,mid,y);
    while(p<mid or q<y)
    {
        if(q>=y or (p<mid and A[p]<=A[q]))B[i++]=A[p++];
        else B[i++]=A[q++],ans+=mid-p;
    }
    for(int i=x;i<y;i++)A[i]=B[i];
}

int main()
{
    n=read<int>();
    for(int i=1;i<=n;i++)A[i]=read<ll>();
    merge_sort(A,B,1,n+1);
    printf("%lld\n",ans);
    return 0;
}
复制代码

 

posted @   Star_Cried  阅读(135)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示