POJ2299(离散化树状数组)

Ultra-QuickSort
Time Limit: 7000MS   Memory Limit: 65536K
Total Submissions: 51852   Accepted: 19039

Description

In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence
9 1 0 5 4 ,

Ultra-QuickSort produces the output
0 1 4 5 9 .

Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.

Input

The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.

Output

For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.

Sample Input

5
9
1
0
5
4
3
1
2
3
0

Sample Output

6
0

Source

总觉得有什么知识点忘记了想还想不起来,终于想到啦,哈哈。这道题的离散化思想在别的题上用到才给我这个提醒想到。
/*此题的第一个技巧是把很大的数HASH成小的范围,第二个是把数组中数字的在对应排完序数组的位置定位。如这道题最后d[i]=j,表示的是第i个数是这些数字中第j小的数。
实现第二个技巧需要明白HASH后的数组储存的是
b:第下标小的数在第储存数的位,而我想知道的是第一位是第几小的数,用D数组从中取出来就行了,从1~N取就会出现d[3]中放置的为1,与b的下标相对应。完成了每一位储存的是第几小的数。
此题的逆序数的算法也很巧妙,先把数组清零,把第一个数在的大小位置放进去,检查之前的大小位置放置了多少个数,就是他之前有多少比他小的数,那他之前就有i-[]个逆序数,
有多少个数与标准顺序不同就有多少个逆序数。*/
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=500005;
int n;
int b[N],c[N],d[N];//
int cmp(int x,int y){
    return c[x]<c[y];
}
int lowbit(int x){
    return x&(-x);
}
void add(int i,int w){
    while(i<=n){
        c[i]+=w;
        i+=lowbit(i);
    }
}
int sum(int i){
    int s=0;
    while(i){
        s+=c[i];
        i-=lowbit(i);
      //  printf("s=%d ",s);
    }
   // printf("
");
    return s;
}
int main(){
    while(scanf("%d",&n)!=EOF&&n){
        for(int i=1;i<=n;i++){
            scanf("%d",&c[i]);
            b[i]=i;
        }
        sort(b+1,b+1+n,cmp);//神奇的哈希大法,使用时间来换取空间,此时b[i]里储存的数字是才c里对应的下标的是的几小的数。b[1]=3表示才第三个数是第一小的。
        memset(c,0,sizeof(c));//此时c已经没有用了,清零方便后续使用
        for(int i=1;i<=n;i++){
            d[b[i]]=i;//把b中储存的数字取出来,赋值给的d数组,这用与之对应,d[3]=1,表示第三个数是第一小的数。至此数据的处理完成,(不过我也没看出来是二维的树状数组啊)。
        }
        long long ans=0;
       // for(int i=1;i<=n;i++) printf("%d ",c[i]);
        for(int i=1;i<=n;i++){
            add(d[i],1);
            int s=sum(d[i]);

            printf("%d-->%d
",d[i],i-s);
            ans+=i-s;
        }
        printf("%I64d
",ans);
    }
}

代码肯定是不会AC的因为我中间输出了检验过程,但思路很重要啊,只要看会了我写的思路,改成AC代码很简单。

原文地址:https://www.cnblogs.com/VectorLin/p/5263190.html