树状数组的离散化 Ultra-QuickSort

离散化,但数据范围太大是所借用的利器,举个例子,有四个数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;
}
posted @ 2011-08-29 10:56  Because Of You  Views(1074)  Comments(0Edit  收藏  举报