归并排序 与 逆序对

洛谷 P1177 【模板】快速排序

归并排序代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,a[N],b[N];
void merge_sort(int l,int r) // 归并排序
// 递归过程类似于树的后序遍历,先把左、右子区间均完成排序后,再合并当前区间
{
    if(l==r)return; // 单个数字,已经有序,直接返回
    int mid=(l+r)/2;
    merge_sort(l,mid); //向下递归左区间[l,mid]
    merge_sort(mid+1,r); //向下递归右区间[mid+1,r]

	// 此时,左右子区间均已有序
    // 合并左右子区间并保持有序,之后向上返回
    int p1=l,p2=mid+1; // p1是左区间指针,p2是右区间指针
    for(int i=l;i<=r;i++) // 合并两个有序的线性表,存于辅助数组b[i]
    {
        if(p1<=mid&&(a[p1]<=a[p2]||p2>r)) b[i]=a[p1++];
        else b[i]=a[p2++];
    }
    for(int i=l;i<=r;i++) // b[i]赋回给a[i]
        a[i]=b[i];
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    merge_sort(1,n); //135ms
    //sort(a+1,a+n+1); //148ms
    for(int i=1;i<=n;i++)
        i==n?printf("%d\n",a[i]):printf("%d ",a[i]);
    return 0;
}
/*
5
5 4 3 2 1
*/

当L=1,R=5时的递归树:(电脑不好画,直接手写了)
在这里插入图片描述

洛谷 P1908 逆序对

归并排序的应用:求逆序对
(其实只是在else那里加了一句代码)

#include <bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,a[N],b[N];
long long ans;
void merge_sort(int l,int r) // 归并排序
{
    if(l==r)return; 
    int mid=(l+r)/2;
    merge_sort(l,mid); 
    merge_sort(mid+1,r); 
    int p1=l,p2=mid+1;
    for(int i=l;i<=r;i++) 
    {
        if(p1<=mid&&(a[p1]<=a[p2]||p2>r)) b[i]=a[p1++];
        else 
        {	
        	b[i]=a[p2++];
        	ans+=mid-p1+1; // 只是在这里加了一句代码
        }
    }
    for(int i=l;i<=r;i++) 
        a[i]=b[i];
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    merge_sort(1,n); 
    printf("%lld\n",ans);
    return 0;
}
/*
4
3 3 2 2

5
5 4 3 2 1
*/

当然也可以直接上 树状数组+离散化 求:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+10;
ll ans,tr[N];
int n,cnt,a[N],t[N];
void add(int i)
{
    while(i<=n)
    {
        tr[i]++;
        i+=(i&-i);
    }
}
ll sum(int i)
{
    ll s=0;
    while(i)
    {
        s+=tr[i];
        i-=(i&-i);
    }
    return s;
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        t[i]=a[i];
    }
    sort(t+1,t+n+1);
    cnt=unique(t+1,t+n+1)-t-1;//是-t-1
    for(int i=1;i<=n;i++)
    {
        a[i]=lower_bound(t+1,t+cnt+1,a[i])-t;//是-t,不是-t-1
        add(a[i]);
        ans+=sum(n)-sum(a[i]);
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ljw_study_in_CSDN/article/details/106280256