树状数组求逆序对

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;
}

posted @ 2018-12-18 16:38  撤云  阅读(1817)  评论(0编辑  收藏  举报
……