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小元素
- import java.util.Scanner;
- public class Main{
- int tree1[];//大顶堆
- int k1;
- int tree2[];//小顶堆
- int k2;
- int M, N;
- int A[];
- public Main(){
- }
- //tree:大顶堆
- void build1(int[] tree, int k) //从下标k开始,大堆向上调整到根
- {
- int p = k;
- while(p != 1)
- {
- if(tree[p] > tree[p / 2]) //如果大于父亲
- {
- int temp = tree[p]; //交换
- tree[p] = tree[p / 2];
- tree[p / 2] = temp;
- }
- p = p / 2; //指向父亲
- }
- }
- //tree:小顶堆
- void build2(int[] tree, int k) //从k开始,小堆向上调整
- {
- int p = k;
- while(p != 1)
- {
- if(tree[p] < tree[p / 2]) //如果小于交亲
- {
- int temp = tree[p]; //交换
- tree[p] = tree[p / 2];
- tree[p / 2] = temp;
- }
- p = p / 2; //指向父亲
- }
- }
- //tree:大顶堆
- void update1(int[] tree, int k){//向下调整大顶堆的根.
- int p = 1; //指向根
- while(2 * p <= k)
- {
- int son;
- if(2 * p == k || tree[2 * p] > tree[2 * p + 1])
- son = 2 * p;
- else
- son = 2 * p + 1;
- if(tree[p] < tree[son]) //如果父节点的值小于左右儿子中最大者,交换
- {
- int temp = tree[p];
- tree[p] = tree[son];
- tree[son] = temp;
- }
- p = son; //指向儿子节点
- }
- }
- //tree:小顶堆
- void update2(int[] tree, int k) //向下调整小顶堆的根,直到k
- {
- int p = 1;
- while(2 * p <= k)
- {
- int son;
- if(2 * p == k || tree[2 * p] < tree[2 * p + 1]) //取左右儿子中的较小者
- son = 2 * p;
- else
- son = 2 * p + 1;
- if(tree[p] > tree[son]) //如果父节点的值大于左右儿子中最大者,交换
- {
- int temp = tree[p];
- tree[p] = tree[son];
- tree[son] = temp;
- }
- p = son;
- }
- }
- public void go(){
- Scanner in=new Scanner(System.in);
- while(in.hasNext())
- {
- M=in.nextInt();
- N=in.nextInt();
- A=new int[M+1];
- tree1=new int[M+1];
- tree2=new int[M+1];
- for(int i = 1; i <= M; ++ i)
- A[i]=in.nextInt();//将M个元素全部读入A
- int pre = 0;
- k1 = k2 = 0;
- for(int i = 1; i <= N; ++ i) //共N轮
- {
- int a=in.nextInt();
- for(int j = pre + 1; j <= a; ++ j) //从A中读入前a个元素到tree2
- {
- tree2[++k2] = A[j]; //读一个,调整一个
- build2(tree2, k2); //构建tree2使之成为最小堆
- }
- pre = a;
- tree1[++ k1] = tree2[1]; //将最小堆的堆顶元素放入tree1中
- build1(tree1, k1); //构建tree1使之成为最大堆
- tree2[1] = tree2[k2 --]; //删除最小堆的堆顶元素,最小堆的最后一个元素放到堆顶
- update2(tree2, k2); //调整,使tree2成为小顶堆
- while(k2 != 0 && tree1[1] > tree2[1])
- {
- int temp = tree1[1];
- tree1[1] = tree2[1];
- tree2[1] = temp;
- update1(tree1, k1); //调整,使tree1成为大顶堆
- update2(tree2, k2); //调整,使tree2成为小顶堆
- }
- System.out.printf("%d\n", tree1[1]);
- }
- }
- }
- public static void main(String args[]){
- Main ma=new Main();
- ma.go();
- }
- }