Preface
求逆序對的方法有兩種一個是歸並排序,一個是樹狀數組。在這里只講怎么用樹狀數組求逆序對
什么是逆序對?
逆序對就是序列中\(a_i>a_j\)且\(i < j\)的有序對。
我們可以先按照權值從大到小排序,現在要求的就是對於一個點有多少在他前面的點下標小於這個點。
那么這個東西怎么弄呢?我們可以用樹狀數組維護。從頭到尾掃一遍,對於每個點,答案就是在這個點下標之前的下標有幾個已經被訪問過,在將這個點在樹狀數組中+1,表示為被訪問過
for(int i=1;i<=n;i++)
ans+=sum(a[i].id),add(a[i].id,1);
但是要注意判重復的元素
code
#include<bits/stdc++.h>
#define int long long
#define rg register
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
return f*x;
}
struct node {
int x,id;
}a[500001];
int c[500001<<2],n,ans,bj[500001];
bool cmp(const node & a , const node & b ){
if(a.x==b.x)
return a.id>b.id;
return a.x>b.x;
}
int lowbit(int x){
return x&(-x);
}
int sum(int x){
int ans=0;
while(x>0){
ans+=c[x];
x-=lowbit(x);
}
return ans;
}
void add(int x,int v){
while(x<=n){
c[x]+=v;
x+=lowbit(x);
}
}
main(){
n=read();
for(int i=1;i<=n;i++)
a[i].id=i,a[i].x=read();
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
ans+=sum(a[i].id),add(a[i].id,1);
printf("%lld",ans);
return 0;
}