ツリー配列の離散化Ultra-QuickSort

1901 ワード

離散化するが、データ範囲が大きすぎるのは借りた利器であり、例を挙げると、4つの数99999991 123,1583のデータ範囲が大きすぎて、木状配列の中のc配列が開いている範囲がデータの範囲であり、この場合には離散化が必要である.4つの数を一度に1 2 3 4(すなわち1番目の数、2番目の数...)と表記し、キー値を並べ替えた後は2 3 4 1(すなわち小さいから大きいまで2番目の数、3番目の数...)の順であるため、2番目の数は最小、すなわちf[2]=1、f[3]=2、f[4]=3、f[1]である=4、つまりキー値を1~nに変えても相対的な大きさは変わらない、すなわち4 1 2 3である.例えば、元の4つの数の逆シーケンスの総和が要求され、現在は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=='
'||c=='\r'); ret=c-'0'; while((c=getchar())!=' '&&c!='
'&&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
",sum); } return 0; }