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