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