今天大家都在做一些自己不会的东西,摸鱼(其实是在写作业,最近生物作业有一些变态)的我也跟着他们学了一下。他们在讨论逆序对,我打开洛谷发现已经做完了,然后就没有然后了。好吧当时也不知道咋过的,今天就重新来复习一下。这道题可以用两种做法来求解,一是归并;二是树状数组。归并首先要维护一个数组,然后好吧现在其实已经距离我写之前的已经过去了两天。
归并排序解法:
#include<cstdio>
#include<iostream>
using namespace std;
int n,a[500010],c[500010];
long long ans;
void msort(int b,int e)
{
if(b==e)
return;
int mid=(b+e)/2,i=b,j=mid+1,k=b;
msort(b,mid);
msort(mid+1,e);
while(i<=mid&&j<=e)
if(a[i]<=a[j]){
c[k++]=a[i++];
} else{
c[k++]=a[j++];
ans+=mid-i+1;
}
while(i<=mid){
c[k++]=a[i++];
}
while(j<=e){
c[k++]=a[j++];
}
for(int l=b;l<=e;l++){
a[l]=c[l];
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
msort(1,n);
printf("%lld",ans);
return 0;
}
树状数组解法:
首先优化需要离散化:
在这段代码中,a[]经过离散,范围就变成了m。解释一下,unique是c++自带的一个函数,表示对一个数列去重,然后返回不重复的元素个数,当然在后面要减去首地址。那么这种离散化对于有重复元素的数列也可以适用,但复杂度相对后面要讲的第二种方法会高些。
const int N=1e5+7;
int t[N],a[N];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
t[i]=a[i];
sort(t+1,t+n+1);
m=unique(t+1,t+n+1)-t-1;
for(int i=1;i<=n;i++)
a[i]=lower_bound(t+1,t+m+1,a[i])-t;
}
第二种,复杂度比上面那一种要优。
但不能处理重复元素。
const int N=1e5+7;
struct Node{
int v,id;
bool operator < (const Node a)const{
return v<a.v;
}//排序用
}a[N];
int n,rank[N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i].v);
a[i].id=i;
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
rank[a[i].id]=i;
}
这种方法直接用结构体存储原本的数列的元素的位置,然后排序以后将他们再重新赋值。那么rank[]就是结构体a[]离散化后的结果。