题目:click
题意:求冒泡排序中的数字交换次数。
其实就是求逆序对。题目中说明了每个数都不一样。先进行离散化处理。
例如:
9 1 0 5 4 实际值
5 2 1 3 4 实际位置
逆序对6。
利用树状数组,query操作返回的时小于b[i]序号的个数,用i-query(b[i])得到该序号的贡献值。
add表示加入个数更新。
形象一下就是,树状数组 底边的数组表示的是小于序号A[i]的个数。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 50100*4
using namespace std;
typedef long long ll;
const int mod=1e9+7;
struct A {
int val;
int bz;
}a[500100];
int c[500100],b[500100];
int n;
bool cmp(struct A t1,struct A t2)
{
return t1.val<t2.val;
}
inline int lowbit(int x)
{
return x&(-x);
}
inline ll query(int x)
{
ll ans=0;
for(int i=x;i>0;i-=lowbit(i))
ans+=c[i];
return ans;
}
inline void add(int x)
{
for(int i=x;i<=n;i+=lowbit(i))
c[i]+=1;
return ;
}
int num[500100];
int main()
{
int i,j;
while(scanf("%d",&n)&&n)
{
for(i=1;i<=n;i++)
{
scanf("%d",&a[i].val);
a[i].bz=i;
}
sort(a+1,a+1+n,cmp);
for(i=1;i<=n;i++)
{
b[a[i].bz]=i;
}
ll ans=0;
for(i=1;i<=n;i++)
c[i]=0;
for(i=1;i<=n;i++)
{
add(b[i]);
ans+=i-query(b[i]);
}
printf("%lld\n",ans);
}
return 0;
}