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);}}


阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 临沂市教育收费系统 临沂市河东区邮编 临沂市区景点 临沂市第四人民医院 临沂市旅游 临沂市房价2019年行情 临沂市公共资源交易中心 临沂市中医医院 临沂市景点 临沂市公共资源交易网 山东省的市 临沂信息港人才招聘 临沂招聘信息港 山东细狗 山东临沂到底多穷 临沂费县有多穷 山东临沂蒙阴县穷不穷 临沂郯城县穷还是富 临沂高铁站 临沂高铁站位置 临沂在线网上第一站 临沂火车站电话 临沂火车站时刻表 山东路 山东地区 临沂糁 临沂糁汤怎么读 正宗临沂糁汤的做法和配料 糁怎么读 玉米糁 玉米糁粥 玉米糁的做法 玉米糁子 玉米糁做法 卧薪尝糁 一身是糁 提心吊糁 米参念什么糁汤 玉米糁怎么吃 苞谷糁 小型玉米糁加工设备