洛谷 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;
}