树状数组求逆序对
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;
}