树状数组的离散化 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; }