题目链接点击打开链接
题意:一个无序的数列,相邻两个swap,求最少需几次转化成从小到大有序数列。
思路:求逆序数。树状数组最典型的应用。因为这道题的数据的值可以很大,如果直接暴力搞,数组肯定开不了那么大,所以要先离散化。
PS 看了一些网上的代码,都是向下求和,向上更新。其实,对于逆序数问题,向上求和,向下更新更方便。另外,结果要用long long保存,因为这个wa了一次。。。orz。。。
AC代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<cmath>
const int MAX=500005;
using namespace std;
int c[MAX],n;
struct node
{
int val,aftval,index;
} point[MAX];
bool cmp1(node a,node b)
{
return a.val<b.val;
}
bool cmp2(node a,node b)
{
return a.index<b.index;
}
int lowbit(int x)
{
return x & (-x);
}
void update(int i, int x)
{
while(i>=1)
{
c[i] = c[i]+x;
i -= lowbit(i);
}
}
int sum(int i)
{
int ans = 0;
while(i<=n+1)
{
ans += c[i];
i += lowbit(i);
}
return ans;
}
int main()
{
while(scanf("%d",&n) && n)
{
int i;
long long ans=0;
memset(c,0,sizeof(c));
for(i=1; i<=n; i++)
{
scanf("%d",&point[i].val);
point[i].index=i;
}
sort(point+1,point+n+1,cmp1);
point[1].aftval=1;
for(i=2; i<=n; i++)
{
if(point[i].val==point[i-1].val) point[i].aftval=point[i-1].aftval;
else point[i].aftval=point[i-1].aftval+1;
}
sort(point+1,point+n+1,cmp2);
for(i=1;i<=n;i++)
{
ans+=sum(point[i].aftval+1);
update(point[i].aftval,1);
}
printf("%lld\n",ans);
}
return 0;
}