离散化,但数据范围太大是所借用的利器,举个例子,有四个数99999999 1 123 1583 数据范围太大,而树状数组中的c数组开的范围是数据的范围,这时候就需要离散化,把四个数一次标号为1 2 3 4(即第一个数,第二个数。。。),按键值排序之后 依次为2 3 4 1(即从小到大排序为第二个数,第三个数。。。),所以,第二个数是最小的,即f[2]=1,f[3]=2,f[4]=3,f[1]=4,也就是把键值变为了1~n,相对大小还是不变的,即4 1 2 3。比如要求原来四个数的逆序数总和,现在就是求4 1 2 3的逆序数总和,大大节省了空间压力(树状数组的长度是数据范围)
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define MAX 500004
int c[MAX],f[MAX];
struct lisan{
int v,num;
}a[MAX];
int get_val()
{
int ret(0);
char c;
while((c=getchar())==' '||c=='\n'||c=='\r');
ret=c-'0';
while((c=getchar())!=' '&&c!='\n'&&c!='\r')
ret=ret*10+c-'0';
return ret;
}
int cmp(lisan a,lisan b)
{
return a.v<b.v;
}
int n;
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int num)
{
while(x<=n)
{
c[x]+=num;
x+=lowbit(x);
}
}
int get_sum(int x)
{
int s=0;
while(x>=1)
{
s+=c[x];
x-=lowbit(x);
}
return s;
}
int main()
{
int i;
while(scanf("%d",&n),n)
{
memset(c,0,sizeof(c));
for(i=1;i<=n;i++)
{
a[i].v=get_val();
a[i].num=i;
}
sort(a+1,a+1+n,cmp);
for(i=1;i<=n;i++)
f[a[i].num]=i;
__int64 sum=0;
for(i=1;i<=n;i++)
{
update(f[i],1);
sum+=i-get_sum(f[i]);
}
printf("%I64d\n",sum);
}
return 0;
}