逆序对

逆序对
(reverse.cpp/c/pas)
【 题意】
什么是逆序对, 不用多介绍, 请你用暴力枚举, 归并以外的方法完成此题。
【 输入格式】
第一行一个整数 n( 1<=n<=100000), 表示有 n 个数。 第二行包含 n 个正整数, 用空格分隔。
【 输出格式】
一个整数, 表示逆序对的对数。
【 样例输入】
5 3
1 4 5 2
【 样例输出】
4

先简单介绍一下逆序对(相信每个OI都知道)。

i<j且f[i]>f[j]的数对(i,j)称为逆序对

逆序对的最简单做法是n^2暴力,两个for语句,但是
当n过大时,此方法会超时,不多介绍。
第二种方法是用归并,这里就用高级数据结构来讲。
逆序对的个数=(所有数对的个数)-(非逆序对数对的个数)
只要求出非逆序对的个数,即可知道逆序对个数。
开一个100000*4的线段树,每读入一个数x,就将其放入节点数
为x的线段树节点里,然后求出区间1——x的和,就是以x为端点
的非逆序对个数。

#include<bits/stdc++.h>
using namespace std;
long long i,j,k,n,m,tot,ans,sum[100005<<2],f[100005],a[100005];
void up(int node){sum[node]=sum[node<<1]+sum[node<<1|1];}
long long read(){
    char c;while(c=getchar(),(c<'0'||c>'9')&&c!='-');
    long long x=0,y=1;if(c=='-') y=-1;else x=c-'0';
    while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';
    return x*y;
}
void updata(int node,int l,int r,int p,int ad){
    if(l==r){
        sum[node]+=ad;
        return;
    }
    int mid=(l+r)/2;
    if(mid>=p) updata(node<<1,l,mid,p,ad);
    else updata(node<<1|1,mid+1,r,p,ad);
    up(node);
}
long long query(int node,int l,int r,int le,int ri){
    if(le<=l&&r<=ri){
        return sum[node];
    }
    long long ans=0;
    int mid=(l+r)/2;
    if(le<=mid) ans+=query(node<<1,l,mid,le,ri);
    if(ri>=mid+1) ans+=query(node<<1|1,mid+1,r,le,ri);
    return ans;
}
void build(int node,int l,int r){
    if(l==r){
        sum[node]=f[l];
        return;
    }
    int mid=(l+r)/2;
    build(node<<1,l,mid);
    build(node<<1|1,mid+1,r);
    up(node);
}
int main()
{
    n=read();for(int i=1;i<=n;i++) a[i]=read();
    build(1,1,100005);
    for(int i=1;i<=n;i++){
        updata(1,1,100005,a[i],1);
        tot+=query(1,1,100005,1,a[i])-1;
    }
    k=1;
    while(k<n){
        ans+=k;
        k++;
    }
    printf("%lld",ans-tot);
    return 0;
}
原文地址:https://www.cnblogs.com/stevensonson/p/7612203.html