POJ-2299(树状数组-应用- 求逆序数)

题目链接:http://poj.org/problem?id=2299

这是我第一次做树状数组的题:要是说不好别打脸。。。

题意:这个题目说得很清楚就是要求  :在 每一个数     当前位之前的数比自己大的个数   的  总和

这个就是我们所说的        逆序数,如    5    2    1    4    3

                                                                          0     1    2    1    2            ans=6

至于怎么求呢,其实看出来和前缀和应该有关。所以用到了树状数组(瞎扯的。。。)

离散化+求和。

1、所谓的离散化,就是只把a[i]的值看成第几大即可,数字本身只用于比较大小,没有实际意义。

所以设结构体。node{     int x,No;    }利用X来排序,然后用No做下标   另外开数组aa[1~n].

2、利用前缀和来求逆序数,

for(i=1;i<=n;i++){

            updata(aa[i],1);                         //        往后加    1

            ans+=   i - getsum( aa[ i ] );    //        原理不明白。。。

}

贴上代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=500005;
int n,aa[maxn],c[maxn];
typedef long long ll;
typedef struct node{
    int x,No;
}node;
node a[maxn];
int lowbit(int x){
    return x&(-x);
}
void updata(int t,int value){
    int i;
    for(int i=t;i<=n;i+=lowbit(i)){
        c[i]+=value;
    }
}
int getsum(int x){
    int i,temp=0;
    for(i=x;i>=1;i-=lowbit(i)){
        temp+=c[i];
    }
    return temp;
}
bool cmp(node a,node b){
    return a.x<b.x;
}
int main()
{
    int i,j;
    while(~scanf("%d",&n),n){
        for(i=1;i<=n;i++){
            scanf("%d",&a[i].x);
            a[i].No=i;
        }
        sort(a+1,a+1+n,cmp);
        for(i=1;i<=n;i++){
            aa[a[i].No]=i;
        }
        memset(c,0,sizeof(c));
        ll ans=0;
        for(i=1;i<=n;i++){
            updata(aa[i],1);
            //printf("i:   %d   getsum(aa[i]): %d  i-getsum[aa[i]] :%d\n",i,getsum(aa[i]),i-getsum(aa[i]));
            ans+=i-getsum(aa[i]);
        }
        cout<<ans<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/z_sea/article/details/80328691