题目链接: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;
}