package main

import (
	"math"
)

// 大根堆小根堆
// 最终取中间的两个元素作为中位数或者取中间一个
// 左边取最大的,因此使用排序后是递增序列的大根堆
// 右边取最小的,因此使用排序后是递减序列的小根堆
// 需要保证所有右侧元素都比左侧堆元素大
// 为了保证两侧元素均匀分布,我们可以设置,如果当前堆总长度为奇数时插入左侧大根堆,否则插入右侧
// 如果插入某个元素时,它原本应该分配到右边,但是它的值却没有左侧大根堆堆顶元素大怎么办?
// 先将左侧堆顶元素移除压入右侧小根堆,然后将新元素压入大根堆
// 同理,将右侧小根堆堆顶元素移除,插入到左侧,然后将新元素插入到右侧
// 首先,我们需要先实现了大根堆和小根堆(有序队列形式的(支持 Push 和 Pop 操作))
type smallHeap struct {
	Size int
	Array []int
}

func (sh *smallHeap) Push(x int) {
	sh.Array = append(sh.Array, x)
	// 插入索引
	index := sh.Size
	sh.Size++

	// 向上调整
	for index >= 0 {
		root := (index-1)/2

		if sh.Array[root] > sh.Array[index] {
			sh.Array[root], sh.Array[index] = sh.Array[index], sh.Array[root]
			index = root
		} else {
			break
		}
	}
}

func (sh *smallHeap) Pop() int {
	if sh.Size == 0 {
		return math.MinInt
	}
	// 弹出堆顶元素
	x := sh.Array[0]
	// 首尾交换
	sh.Array[0], sh.Array[sh.Size-1] = sh.Array[sh.Size-1], sh.Array[0]
	// 弹出
	sh.Array = sh.Array[:sh.Size-1]
	sh.Size--
	// 向下调整
	root := 0

	for root < sh.Size {
		left, right := 2*root+1, 2*root+2
		if left >= sh.Size {
			break
		}

		if right < sh.Size && sh.Array[right] < sh.Array[left] {
			left = right
		}

		if sh.Array[left] > sh.Array[root] {
			break
		}

		sh.Array[root], sh.Array[left] = sh.Array[left], sh.Array[root]
		root = left
	}

	return x
}


func (sh *smallHeap) Top() int {
	if sh.Size == 0 {
		return math.MinInt
	}

	return sh.Array[0]
}


type bigHeap struct {
	Size int
	Array []int
}

func (bh *bigHeap) Push(x int) {
	bh.Array = append(bh.Array, x)
	// 插入索引
	index := bh.Size
	bh.Size++

	// 向上调整
	for index >= 0 {
		root := (index-1)/2

		if bh.Array[root] < bh.Array[index] {
			bh.Array[root], bh.Array[index] = bh.Array[index], bh.Array[root]
			index = root
		} else {
			break
		}
	}
}

func (bh *bigHeap) Pop() int {
	if bh.Size == 0 {
		return math.MinInt
	}
	// 弹出堆顶元素
	x := bh.Array[0]
	// 首尾交换
	bh.Array[0], bh.Array[bh.Size-1] = bh.Array[bh.Size-1], bh.Array[0]
	// 弹出
	bh.Array = bh.Array[:bh.Size-1]
	bh.Size--
	// 向下调整
	root := 0

	for root < bh.Size {
		left, right := 2*root+1, 2*root+2
		if left >= bh.Size {
			break
		}

		if right < bh.Size && bh.Array[right] > bh.Array[left] {
			left = right
		}

		if bh.Array[left] < bh.Array[root] {
			break
		}

		bh.Array[root], bh.Array[left] = bh.Array[left], bh.Array[root]
		root = left
	}
	
	return x
}

func (bh *bigHeap) Top() int {
	if bh.Size == 0 {
		return math.MinInt
	}

	return bh.Array[0]
}

var small smallHeap
var big bigHeap

// 左大右小
func Insert(num int){
	size := small.Size + big.Size
	if size % 2 == 0 {
		if small.Size > 0 && num > small.Top() {
			big.Push(small.Pop())
			small.Push(num)
		} else {
			big.Push(num)
		}
	} else {
		if big.Size > 0 && num < big.Top() {
			small.Push(big.Pop())
			big.Push(num)
		} else {
			small.Push(num)
		}
	}
}

func GetMedian() float64{
	size := small.Size + big.Size
	if size % 2 == 1 {
		return float64(big.Top())
	} else {
		return float64(small.Top()+big.Top())/2
	}
}