20200922

今天大家都在做一些自己不会的东西,摸鱼(其实是在写作业,最近生物作业有一些变态)的我也跟着他们学了一下。他们在讨论逆序对,我打开洛谷发现已经做完了,然后就没有然后了。好吧当时也不知道咋过的,今天就重新来复习一下。这道题可以用两种做法来求解,一是归并;二是树状数组。归并首先要维护一个数组,然后好吧现在其实已经距离我写之前的已经过去了两天。

归并排序解法:

#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[]离散化后的结果。

posted on 2020-09-23 07:50  fishsit  阅读(69)  评论(0编辑  收藏  举报

导航