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