大(小)顶堆练习: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小元素



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();
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值