大(小)顶堆练习:POJ 1442

 POJ1442题意:
ADD(a)表示向集合中增加元素a,get表示取出第k小元素,k根据get出现的次数不断变化,出现多少次取第几小数。
样例:

Sample Input

7 4
3 1 -4 2 8 -1000 2
1 2 6 6
Sample Output

3
3
1
2

解释:
输入 n = 7 m =4,然后第一行输入n个数,然后另一行输入m个数

index = 1

1:输出n个数中前1个数中的第Index(1)小值

index=2

2:输出n个数中前2个数中的第index(2)小值

index=3

6:输出n个数中前6个数中的第index(3)小值

index=4

6:输出n个数中前6个数中的第index(4)小值


输入保证m个数单调递增

题解:每次取第k小元素,k不断更新。使用两个堆,来完成。 小顶堆负责,选出最小的元素,大顶堆负责,选出k个元素中最大的元素,即第k小元素
 

Java代码 复制代码 收藏代码
  1. import java.util.Scanner;
  2.  
  3. public class Main{
  4. int tree1[];//大顶堆
  5. int k1;
  6. int tree2[];//小顶堆
  7. int k2;
  8. int M, N;
  9. int A[];
  10.  
  11. public Main(){
  12. }
  13.  
  14. //tree:大顶堆
  15. void build1(int[] tree, int k) //从下标k开始,大堆向上调整到根
  16. {
  17. int p = k;
  18. while(p != 1)
  19. {
  20. if(tree[p] > tree[p / 2]) //如果大于父亲
  21. {
  22. int temp = tree[p]; //交换
  23. tree[p] = tree[p / 2];
  24. tree[p / 2] = temp;
  25. }
  26. p = p / 2; //指向父亲
  27. }
  28. }
  29. //tree:小顶堆
  30. void build2(int[] tree, int k) //从k开始,小堆向上调整
  31. {
  32. int p = k;
  33. while(p != 1)
  34. {
  35. if(tree[p] < tree[p / 2]) //如果小于交亲
  36. {
  37. int temp = tree[p]; //交换
  38. tree[p] = tree[p / 2];
  39. tree[p / 2] = temp;
  40. }
  41. p = p / 2; //指向父亲
  42. }
  43. }
  44.  
  45. //tree:大顶堆
  46. void update1(int[] tree, int k){//向下调整大顶堆的根.
  47. int p = 1; //指向根
  48. while(2 * p <= k)
  49. {
  50. int son;
  51. if(2 * p == k || tree[2 * p] > tree[2 * p + 1])
  52. son = 2 * p;
  53. else
  54. son = 2 * p + 1;
  55. if(tree[p] < tree[son]) //如果父节点的值小于左右儿子中最大者,交换
  56. {
  57. int temp = tree[p];
  58. tree[p] = tree[son];
  59. tree[son] = temp;
  60. }
  61. p = son; //指向儿子节点
  62. }
  63. }
  64.  
  65. //tree:小顶堆
  66. void update2(int[] tree, int k) //向下调整小顶堆的根,直到k
  67. {
  68. int p = 1;
  69. while(2 * p <= k)
  70. {
  71. int son;
  72. if(2 * p == k || tree[2 * p] < tree[2 * p + 1]) //取左右儿子中的较小者
  73. son = 2 * p;
  74. else
  75. son = 2 * p + 1;
  76. if(tree[p] > tree[son]) //如果父节点的值大于左右儿子中最大者,交换
  77. {
  78. int temp = tree[p];
  79. tree[p] = tree[son];
  80. tree[son] = temp;
  81. }
  82. p = son;
  83. }
  84. }
  85.  
  86. public void go(){
  87. Scanner in=new Scanner(System.in);
  88. while(in.hasNext())
  89. {
  90. M=in.nextInt();
  91. N=in.nextInt();
  92.  
  93. A=new int[M+1];
  94. tree1=new int[M+1];
  95. tree2=new int[M+1];
  96. for(int i = 1; i <= M; ++ i)
  97. A[i]=in.nextInt();//将M个元素全部读入A
  98.  
  99. int pre = 0;
  100. k1 = k2 = 0;
  101. for(int i = 1; i <= N; ++ i) //共N轮
  102. {
  103. int a=in.nextInt();
  104. for(int j = pre + 1; j <= a; ++ j) //从A中读入前a个元素到tree2
  105. {
  106. tree2[++k2] = A[j]; //读一个,调整一个
  107. build2(tree2, k2); //构建tree2使之成为最小堆
  108.  
  109. }
  110. pre = a;
  111. tree1[++ k1] = tree2[1]; //将最小堆的堆顶元素放入tree1中
  112. build1(tree1, k1); //构建tree1使之成为最大堆
  113. tree2[1] = tree2[k2 --]; //删除最小堆的堆顶元素,最小堆的最后一个元素放到堆顶
  114. update2(tree2, k2); //调整,使tree2成为小顶堆
  115. while(k2 != 0 && tree1[1] > tree2[1])
  116. {
  117. int temp = tree1[1];
  118. tree1[1] = tree2[1];
  119. tree2[1] = temp;
  120. update1(tree1, k1); //调整,使tree1成为大顶堆
  121. update2(tree2, k2); //调整,使tree2成为小顶堆
  122. }
  123. System.out.printf("%d\n", tree1[1]);
  124. }
  125. }
  126. }
  127.  
  128. public static void main(String args[]){
  129. Main ma=new Main();
  130. ma.go();
  131. }
  132. }  

你可能感兴趣的:(S)