LUOGU P1908 逆序对

题目描述

猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i

解题思路

有两种解法,第一种是树状数组,首先先按照数字排序,之后进行对下标的单点修改和区间查询。第二种是归并排序,每次合并时ans+=mid-i+1;复杂度都是O(nlogn)

代码

1、树状数组

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>

using namespace std;
const int MAXN = 40005;

int n,f[MAXN],ans;

struct DATA{
    int a,id;
}t[MAXN];

inline bool cmp(DATA A,DATA B){
    return A.a>B.a;
}

inline void add(int x,int y){
    for(;x<=n;x+=x&-x)
        f[x]+=y;
}

inline int query(int x){
    int ret=0;
    for(;x;x-=x&-x)
        ret+=f[x];
    return ret;
}

int main(){
    scanf("%d",&n);
    for(register int i=1;i<=n;i++){
        scanf("%d",&t[i].a);
        t[i].id=i;
    }
    sort(t+1,t+1+n,cmp);
    for(register int i=1;i<=n;i++){
        add(t[i].id,1);
        ans+=query(t[i].id-1);
    }
    printf("%d",ans);
    return 0;
}

2、归并排序

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int MAXN = 40005;

int n,a[MAXN],cpy[MAXN];
int ans;

inline void merge_sort(int l,int r){
    if(l==r) return;
    int mid=l+r>>1;
    merge_sort(l,mid);
    merge_sort(mid+1,r);
    int i=l,j=mid+1,k=l;
    while(i<=mid && j<=r){
        if(a[i]>a[j]){
            ans+=mid-i+1;
            cpy[k++]=a[j++];
        }
        else cpy[k++]=a[i++];
    }
    while(i<=mid) cpy[k++]=a[i++];
    while(j<=r)  cpy[k++]=a[j++];
    for(register int i=l;i<=r;i++) a[i]=cpy[i];
}

int main(){
    scanf("%d",&n);
    for(register int i=1;i<=n;i++) scanf("%d",&a[i]);
    merge_sort(1,n);
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/sdfzsyq/p/9676927.html