POJ 2299 Ultra-QuickSort (树状数组)
来源:互联网 发布:福建摩尔软件靠谱吗 编辑:程序博客网 时间:2024/06/01 20:26
题目链接
题目大意很简单,给一个序列的数字,只有相邻的数字可以交换位置,最后要使之顺序排列,求总共要进行几次交换。
思路是这样:从1到N个数,只有碰到左边的数比右边的数大时,才需要交换。那么就只要求出每个数,它的右边有多少个比它小的数(即逆序数),然后把求出来的结果加在一起,就是一共需要交换的次数。那又是怎样想到用树状数组呢?
我们知道树状数组可以拿来维护1 - N 这样一个区间的信息,那我们逆向思维一下,既然我们要求一个数的逆序数,也可以反过来,看第 i 个数在 1 到 i-1 这个区间,有多少个比它大,也是一样的。那么新的问题又来了,我们怎么知道,1 到 i-1 有多少个比它大的数,最简单的就是遍历 1到i-1,这办法显然达不到时间要求。那用树状数组可以来优化它,比如,用树状数组来维护比从 1到i-1 比第 i 个数大的数,这样貌似行得通,但事实上,我们无法保证,这个点维护的这个值是否对后面的第 j 个点也有效,因为可能存在 i j 之间的值,因此这种办法也不行。
再逆向思维一下,我们用树状数组(用sum[]表示)来维护从 1到i-1 中比第 i 个数小的值,那么比第 i 个数大的就是 (i-1) - sum[i-1],这里我们可以直接换成 i - sum[i],因为在真正使用的时候,sum[i]会被立即赋值。说到这其实还有个问题没解决:这样的方法依然跟上面提到的记录大的数一样,无法保证对后面的数都有效,怎么办?
那么我们就让这些数按照输入的顺序来查它左边有多少个比它小的。具体实现方法如下:
如测试样例 9 1 0 5 4 ; 9是第一个输入的,我们就先将sum[9]置1,表示该位已存在了,我们只需要统计,此时sum[]数组中从1到9位有多少已经被置1(即表示已经出现则这些数在9的左边)。这时候,问题就彻底变成了树状数组的模型了,每次都会单点更新 i,然后查 1到 i的和。
这题的整体逻辑就是这样,感觉讲得有点乱。。。
但这提到这里还没结束,看看题中a[i]的范围,10位9,超了int范围了,数组开不了这么大,所以我们需要对数据进行离散化,通过这种方法,来使数据更紧凑。
具体方法,直接上代码吧。。。。
说明下,Node中的value记录本身的值,rank用来记录,这个数是第几个输入的,然后,seq[]数组是离散化后的结果,下标表示原先的输入顺序,值表示离散化后的值(其实就是在把所有数顺序排之后,这个数是第几个,然后就用这个序号来表示这个数)
import java.util.Arrays;import java.util.Scanner;class Node implements Comparable<Node>{int value, rank;public Node(int value, int rank) {this.value = value;this.rank = rank;}@Overridepublic int compareTo(Node o) {return value - o.value;}}public class Main{static Scanner sc = new Scanner(System.in);static int n;static Node [] node;static int [] seq;static int [] sum;static void update(int x) {while(x <= n) {sum[x] += 1;x += x & -x;}}static int sum(int x) {int ans = 0;while(x > 0) {ans += sum[x];x -= x & -x;}return ans;}public static void main(String[] args) {while(true) {n = sc.nextInt();if(n == 0) break;node = new Node[n];seq = new int[n+1];sum = new int[n+1];for(int i = 0; i < n; i++) {node[i] = new Node(sc.nextInt(), i + 1);}Arrays.sort(node);for(int i = 1; i <= n; i++) {//第 i个大的数字,是第rank个进来的seq[node[i-1].rank] = i;}long ans = 0;for(int i = 1; i <= n; i++) {update(seq[i]);ans += i - sum(seq[i]);}System.out.println(ans);}System.exit(0);}}