首先通过题目看看如何考察逆序数,什么是逆序数?逆序数就是找前面有几个比自己大的数
即如果i<j&&a[i]>a[j] 则a[i]和a[j]构成一个逆序对

这里排序求交换次数比正好就是我们前面讲到的逆序对吗?
因此我们首先就想到了o(logn)方法的归并排序 mergesort(int l,int r)
归并排序的思路就是:先二分分到不能再分,保证(l<r),再将两个有序的序列合并起来。
如一个序列a[7]={100,29,8,9,10,5} 对齐归并排序步骤如下:
100,29,8,9,10,5
{100,29,8} {9,10,5}
{100} {29,8} {9,10} {5}
合并:
{100}{8,29},{9,10}{5}
{8,29,100},{5,9,10}
{5,8,9,10,29,100}
我们发现当和并的时候如果左边的a[p]>a[q],则产生了逆序,p-mid这一段的数都对a[q]构成逆序,因为他们是从小到大有序的了。
因此ans+=mid-p+1就是逆序对数
写出代码:
#include<iostream>
using namespace std;
int a[6]={100,29,8,9,10,5},b[6];
int ans=0;
void merge(int l,int mid,int r){
cout<<l<<" "<<mid<<" "<<r<<" "<<endl;
int p=l,q=mid+1,i=l;
while(p<=mid&&q<=r){//左右两部分都不要为空
//从左半数组复制到辅助数组
if(a[p]<=a[q]){
b[i++]=a[p++];
}else{ //从右半数组复制到辅助数组
b[i++]=a[q++];
ans+=mid-p+1;
}
}
//处理剩下的,一部分变为空了
while(p<=mid){
b[i++]=a[p++];
}
while(q<=r){
b[i++]=a[q++];
}
//写会原来的数组
for(int j=l;j<=r;j++){
a[j]=b[j];
}
}
void mergesort(int l ,int r){
if(r-l>0){
int mid=(l+r)/2;
int p=l,q=mid+1,i=l; //p为左边的第一个,q为右边的第一个
mergesort(l,mid);
mergesort(mid+1,r);
merge(l,mid,r);
}
}
int main(){
mergesort(0,5);
cout<<ans;
return 0;
}
//100,29,8,9,10,5
//0-2 3-5 {100,29,8} {9,10,5}
//0-1 3-4 {100,29} 8 {9,10} 5
//下面来看看树状数组,树状数组用于求解a[1]-a[i]区间和及单点修改问题。
#include<iostream>
using namespace std;
int n,a[10010],c[10010];
int lowbit(int x)
{
return x&(-x);
}
//C[i] = A[i - 2k+1] + A[i - 2k+2] + ... + A[i]
//单点修改更新了a[i] 要更新对应的c[xxx],其中c[xxx]包含a[i]
int update(int i,int k){
while(i<=n){
c[i]+=k;
i+==lowbit(i);
}
}
//求1到i的区间和a[1]+...+a[i]
//c[x1]+c[x2]+..+c[xx] xx=i...i-lowbit[i]..1
int getsum(int i){
int sum=0;
while(i>0){
sum+=c[i];
i-=lowbit(i);
}
return sum;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
update(i,a[i]);//输入等于单点修改值
}
return 0;
}如何用树状数组求解逆序数呢?
对于序列t 100,29,8,9,10,5
1 2 3 4 5 6
a[100]=1 a[29]=1 a[8]=1 a[9]=1 a[10]=1 a[5]=1
即update(100,1),update(29,1),update(8,1)......
然后
getsum(100)为a[1]+...+a[100] t[1]前面小于t[1]的个数 i-getsum(100) 就是第i个数前面大于t[i]的个数
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=1e5+5;
const int mod=99999997;
int n,c[N],temp[N],t[N];
long long ans=0;
struct node
{
int w;
int id;
}a[N],b[N];
int R()
{
int f=0;
char c;
for(c=getchar();c<'0'||c>'9';c=getchar());
for(;c<='9'&&c>='0';c=getchar())
f=(f<<3)+(f<<1)+c-'0';
return f;
}
bool comp(node x,node y)
{
return x.w<y.w;
}
inline void merge(int x,int mid,int y)
{
int i=x,j=mid+1,head=x;
while(i<=mid&&j<=y)
{
if(c[i]<=c[j])
temp[head++]=c[i++];
else
{
ans=(ans+mid-i+1)%mod;
temp[head++]=c[j++];
}
}
while(i<=mid) temp[head++]=c[i++];
while(j<=y) temp[head++]=c[j++];
for(i=x;i<=y;i++)
c[i]=temp[i];
}
inline void mergesort(int a,int b)
{
if(a==b) return;
int mid=(a+b)/2;
mergesort(a,mid);
mergesort(mid+1,b);
merge(a,mid,b);
}
int lowbit(int x){
return x&(-x);
}
void update(int i,int k){
while(i<=n){
t[i]+=k;
i+=lowbit(i);
}
}
int getsum(int i){
int sum=0;
while(i>0){
sum+=t[i];
i-=lowbit(i);
}
return sum;
}
int main()
{
//freopen("a.in","r",stdin);
n=R();
for(int i=1;i<=n;i++)
{
a[i].w=R();
a[i].id=i;
}
for(int i=1;i<=n;i++)
{
b[i].w=R();
b[i].id=i;
}
sort(a+1,a+n+1,comp);
sort(b+1,b+n+1,comp);
for(int i=1;i<=n;i++)
c[b[i].id]=a[i].id;
for(int i=1;i<=n;i++){
update(c[i],1);
ans=(ans+i-getsum(c[i]))%mod;
}
cout<<ans<<endl;
return 0;
}参考资料:树状数组概念 https://www.cnblogs.com/xenny/p/9739600.html
归并排序求逆序数 https://blog.csdn.net/qq_41550842/article/details/81215935
树状数组求逆序数 https://blog.csdn.net/m0_38033475/article/details/80330157

有话要说...