洛谷P1908 逆序对
逆序对就不用解释了,题上也说的很清楚。那我分别用归并排序和树状数组来解决一下这道题目。
归并排序
我们都知道,归并排序是通过把大区间一直分,分成小区间,然后小区间排序好了之后,再合并成大区间。也就是说在n*logn的复杂度的情况下给这个数组排了一下序列,在排序过程中加上一句代码ans+=mid-left+1,只要排在后面但是比前面的数小,位置差就是逆序数。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
using namespace std;
const int N=5e5+10;
int a[N],s[N];
long long ans;
void msort(int l,int r)
{
if(l==r)
{
return;
}
int mid=(l+r)>>1;
msort(l,mid);
msort(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r)
{
if(a[i]<=a[j])
{
s[k]=a[i];
i++,k++;
}
else
{
s[k]=a[j];
j++,k++;
ans+=mid-i+1;
}
}
while(i<=mid)
{
s[k]=a[i];
k++,i++;
}
while(j<=r)
{
s[k]=a[j];
k++,j++;
}
for(int q=l;q<=r;q++)
{
a[q]=s[q];
}
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
ans=0;
msort(1,n);
printf("%lld\n",ans);
return 0;
}
树状数组
用树状数组,因为这道题数据的值域有点大,但是数量并不是很多,所以要对数据进行离散化处理,离散化之后,对数据进行插入,插入的时候,随便求一下当前这个数前面已经插入了多少个数,然后用这个数的位置来减去前面的数的个数,就是这个数的逆序数,所有的数的逆序数之和就是这整个数列的逆序数。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
using namespace std;
const int N=5e5+10;
int a[N],s[N];
long long ans;
void msort(int l,int r)
{
if(l==r)
{
return;
}
int mid=(l+r)>>1;
msort(l,mid);
msort(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r)
{
if(a[i]<=a[j])
{
s[k]=a[i];
i++,k++;
}
else
{
s[k]=a[j];
j++,k++;
ans+=mid-i+1;
}
}
while(i<=mid)
{
s[k]=a[i];
k++,i++;
}
while(j<=r)
{
s[k]=a[j];
k++,j++;
}
for(int q=l;q<=r;q++)
{
a[q]=s[q];
}
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
ans=0;
msort(1,n);
printf("%lld\n",ans);
return 0;
}