逆序数的应用
本题的意思:很多奶牛有暴躁值,每个奶牛都有标号,当这些奶牛交换位置时,花费的时间=这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;
}