HDU 2838 逆序数应用

逆序数的应用

本题的意思:很多奶牛有暴躁值,每个奶牛都有标号,当这些奶牛交换位置时,花费的时间=这2个奶牛的各自的暴躁值之和。求共交换多少次用树状数组就可以了。求暴躁值query(n)-query(x)就行了

例如:2 3 1   ,共交换2次,才能变成 1 2 3; 1用了2次,次数*当前的值+前面比该数大的数的和;  2 3  比1 大,且在1的前头,所以是 1*2+2+3=7;也就是1*2+5=7; 5是这样算的,query(n)-query(x);共3个数,6-1=5;query()里是放的数的和;

#include <iostream>

#include <stdio.h>

#include <cstring>

using namespace std;

const int maxn=100008;

struct sa {

   int xu;//存放次数

   long long sum;//存放和

};

//sa i;

sa tree[maxn];

int n;

int lowbit(int t)

{

         return t & (-t);

}

 

void update(int pos,int su,int val)

{

         while(pos<=n)

         {

 

                   tree[pos].sum+=su;//和

                   tree[pos].xu+=val;//次数

                   pos+=lowbit(pos);

         }

 

 

 

}

 

int query_su(int pos)//次数

{

         int sum=0;

         while(pos>0)

         {

                   sum+=tree[pos].xu;

                   pos-=lowbit(pos);

         }

         return sum;

}

 

long long query_sum(int pos)//和

{

         long long sum=0;

         while(pos>0)

         {

                   sum+=tree[pos].sum;

                   pos-=lowbit(pos);

 

 

         }

         return sum;

 

}

 

int main()

{

 

int x;

long long ans=0;

while(cin>>n)

{

         memset(tree,0,sizeof(tree));

         //maxn=n;

         ans=0;

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

         {

                   scanf("%d",&x);

                   update(x,x,1);

                   long long tmp=i-query_su(x);//得到逆序对的个数,tmp必须是64位的

                   if (tmp!=0)

                   {

        long long k2=query_sum(n)-query_sum(x);

        ans=ans+tmp*x+k2;   //如果tmp是32位的。tmp*x会溢出

 

 

                   }

 

         }

     if (n==1)

     printf("%d\n",0);

     else

     printf("%I64d\n",ans);

}

 

 

    //cout << "Hello world!" << endl;

    return 0;

}

 

 

 

 

 

posted @ 2012-09-23 07:36  兴安黑熊  阅读(303)  评论(0编辑  收藏  举报