51Nod 1019 逆序数

来源:互联网 发布:linux命令存储 编辑:程序博客网 时间:2024/05/22 13:39
题意:在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4。给出一个整数序列,求该序列的逆序数。
解题思路:树状数组求逆序数.很经典的题目,因为树状数组下标是从1开始的,所以用数组存的时候下标也要从1开始。然后给一个数组排序,再二分查找在排序后的数组中的位置。举个例子:2 4 3 1,排序后就是1 2 3 4,然后原数组中第一个元素2在第二个位置,4在第四个位置,然后找逆序就是该位置之后的元素个数,因为已经排好序了嘛,后面的元素肯定比前面的大,如果在该元素出现之前,已经有比它大的元素出现了,那么就是一个逆序啊
代码:
#include <iostream>#include <algorithm>#include <cstring>#include <string>#include <cstdio>#include <cmath>#include <vector>#include <set>#include <map>#include <queue>using namespace std;const int maxn=50000+5;int bit[maxn];int n;int a[maxn],b[maxn];int lowbit(int x){    return (x&-x);}int sum(int i){    int s=0;    while(i>0)    {        s+=bit[i];        i-=lowbit(i);    }    return s;}void add(int i,int x){    while(i<=n)    {        bit[i]+=x;        i+=lowbit(i);    }}void init(){    memset(bit,0,sizeof(bit));    memset(a,0,sizeof(a));    memset(b,0,sizeof(b));}int main(){    while(scanf("%d",&n)==1)    {        init();        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);            b[i]=a[i];        }        sort(a+1,a+n+1);        int ans=0;        for(int i=1;i<=n;i++)        {            int pos=lower_bound(a+1,a+n+1,b[i])-a;            add(pos,1);            ans+=sum(n)-sum(pos);        }        printf("%d\n",ans);    }    return 0;}