求逆序对
- 逆序对是什么呢?就是说在一个序列中,如果i<j但是\(a_i>a_j\)那么(\(a[i],a[j]\))就是一个逆序对,是无序的。
- 通俗的说,逆序对就是就是一个数与在它后面且比他小的数组成的数对。
- 树状数组可以用来求逆序对,是利用它能求前缀/后缀和的原理
- 将一个1~N的数组由后向前遍历,每次遍历到\(a_i\)时,在树状数组下标为\(a_i\)的地方+1,并向后一直到N维护前缀和,遍历到\(a[i]\)时,求Q(\(a[i]-1\))即\(a[i]\)与其后面的数组成的逆序对个数
(注意一下离散化方法,因为洛谷上用map会超时)
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=5e5+5;
int t[maxn],a[maxn],n,tot;
long long ans;
inline long long rd(){
register int x=0,f=0;register char ch=getchar();
while(ch<'0'||ch>'9')f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return f?-x:x;
}
void A(int x,int a){
for(;x<=n;x+=x&-x)t[x]+=a;
}
int Q(int x){
int ans=0;
for(;x;x-=x&-x)ans+=t[x];
return ans;
}
struct Node{
int id,data;
}node[maxn];
bool cmp(Node a,Node b){
return a.data<b.data;
}
int main(){
// freopen("1.in","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;++i){
node[i].data=rd();
node[i].id=i;
}
sort(node+1,node+1+n,cmp);//离散化
for(int i=1;i<=n;++i){
if(node[i].data>node[i-1].data){//赋予其小点的数,我们只需要知道其相对位置即可
a[node[i].id]=i;
}else a[node[i].id]=a[node[i-1].id];//处理相等情况,离散化为一个数值
}
for(int i=n;i>=1;--i){
ans+=(long long)Q(a[i]-1);
A(a[i],1);
}
printf("%lld\n",ans);
return 0;
}