POJ2299(离散化树状数组)
Ultra-QuickSort
Time Limit: 7000MS | Memory Limit: 65536K | |
Total Submissions: 51852 | Accepted: 19039 |
Description
![](http://poj.org/images/2299_1.jpg)
Ultra-QuickSort produces the output
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("\n"); 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\n",d[i],i-s); ans+=i-s; } printf("%I64d\n",ans); } }
代码肯定是不会AC的因为我中间输出了检验过程,但思路很重要啊,只要看会了我写的思路,改成AC代码很简单。