歸併排序 與 逆序對

洛谷 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章