結果

問題 No.1479 Matrix Eraser
ユーザー 草苺奶昔草苺奶昔
提出日時 2023-12-22 22:42:41
言語 Go
(1.22.1)
結果
AC  
実行時間 640 ms / 3,000 ms
コード長 19,190 bytes
コンパイル時間 11,081 ms
コンパイル使用メモリ 224,724 KB
実行使用メモリ 66,336 KB
最終ジャッジ日時 2023-12-22 22:43:07
合計ジャッジ時間 24,756 ms
ジャッジサーバーID
(参考情報)
judge15 / judge11
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
6,676 KB
testcase_01 AC 1 ms
6,676 KB
testcase_02 AC 1 ms
6,676 KB
testcase_03 AC 1 ms
6,676 KB
testcase_04 AC 1 ms
6,676 KB
testcase_05 AC 1 ms
6,676 KB
testcase_06 AC 1 ms
6,676 KB
testcase_07 AC 76 ms
11,664 KB
testcase_08 AC 122 ms
12,396 KB
testcase_09 AC 259 ms
21,924 KB
testcase_10 AC 472 ms
38,168 KB
testcase_11 AC 304 ms
35,100 KB
testcase_12 AC 91 ms
11,280 KB
testcase_13 AC 119 ms
12,396 KB
testcase_14 AC 95 ms
12,368 KB
testcase_15 AC 22 ms
7,756 KB
testcase_16 AC 106 ms
12,408 KB
testcase_17 AC 565 ms
54,268 KB
testcase_18 AC 573 ms
58,976 KB
testcase_19 AC 582 ms
57,500 KB
testcase_20 AC 572 ms
60,224 KB
testcase_21 AC 568 ms
57,192 KB
testcase_22 AC 574 ms
57,920 KB
testcase_23 AC 565 ms
56,648 KB
testcase_24 AC 558 ms
55,928 KB
testcase_25 AC 565 ms
65,372 KB
testcase_26 AC 572 ms
59,212 KB
testcase_27 AC 224 ms
13,000 KB
testcase_28 AC 222 ms
12,080 KB
testcase_29 AC 226 ms
14,896 KB
testcase_30 AC 225 ms
12,868 KB
testcase_31 AC 227 ms
12,868 KB
testcase_32 AC 146 ms
16,444 KB
testcase_33 AC 146 ms
18,516 KB
testcase_34 AC 146 ms
16,448 KB
testcase_35 AC 147 ms
16,448 KB
testcase_36 AC 148 ms
17,844 KB
testcase_37 AC 103 ms
20,096 KB
testcase_38 AC 312 ms
13,728 KB
testcase_39 AC 640 ms
66,336 KB
testcase_40 AC 1 ms
6,676 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	// Movie()
	// MerryChristmas()
	// demo()
	// Hakata()
	Yuki1479()
}

// https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1566
// 太郎君需要在夏假期间`每天`都看一部电影,每部电影上映时间为[a,b](1<=a<=b<=31).
// 如果是第一次看这部电影,他会得到100的幸福度,
// 如果是重复看,他会得到50的幸福度。他的目标是最大化他的总幸福度。
//
// n<=100
//
// 将每一天和每一部电影看作图的一个节点,如果某一天可以观看某部电影(即电影的上映日期包含这一天),
// 那么就在这两个节点之间连一条边。这样,我们就得到了一个二分图,
// 其中一部分节点代表日期,另一部分节点代表电影。
// 在这个二分图中,找到一个最大匹配,就相当于找到一个方式,
// 使得太郎君在每一天都看一部电影,并且尽可能地使得看的电影是第一次看,从而使得他得到的幸福度最大。
func Movie() {
	in, out := bufio.NewReader(os.Stdin), bufio.NewWriter(os.Stdout)
	defer out.Flush()

	var n int
	fmt.Fscan(in, &n)
	OFFSET := 31
	intervals := make([][2]int, n)
	for i := 0; i < n; i++ {
		fmt.Fscan(in, &intervals[i][0], &intervals[i][1])
		intervals[i][0]--
	}
	graph := make([][]int, OFFSET+n)
	isIn := make([]bool, OFFSET)
	for i := 0; i < n; i++ {
		start, end := intervals[i][0], intervals[i][1]
		for v := start; v < end; v++ {
			graph[v] = append(graph[v], OFFSET+i)
			isIn[v] = true
		}
	}
	bm := NewBipartiteMatching(OFFSET+n, graph, nil)
	a := len(bm.MaxMatching())
	b := 0
	for _, v := range isIn {
		if v {
			b++
		}
	}
	fmt.Fprintln(out, (a+b)*50)
}

// https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2251
// 给定一个无向带权图(可能不连通)和q个查询.
// 每个查询形如(pos,time),表示有一个在时间time向房屋pos送货的请求.
// 需要在图中放置人员送货,如何安排最少数量的人完成所有请求(每个人单位移动速度为1)。
// 同一地点和时间最多只有一个请求。
// n<=100 m<=1000 q<=1000
//
// !dag最小可相交路径覆盖=dag最长反链
func MerryChristmas() {
	in, out := bufio.NewReader(os.Stdin), bufio.NewWriter(os.Stdout)
	defer out.Flush()

	solve := func(n, m, q int) {
		adjList := make([][][2]int, n)
		for i := 0; i < m; i++ {
			var u, v, w int
			fmt.Fscan(in, &u, &v, &w)
			adjList[u] = append(adjList[u], [2]int{v, w})
			adjList[v] = append(adjList[v], [2]int{u, w})
		}
		dist := make([][]int, n)
		for i := range dist {
			d, _ := Dijkstra(n, adjList, i)
			dist[i] = d
		}

		queries := make([][2]int, q)
		for i := 0; i < q; i++ {
			var pos, time int
			fmt.Fscan(in, &pos, &time)
			if pos == 0 && time == 0 {
				continue
			}
			queries[i] = [2]int{pos, time}
		}

		dag := make([][]int, q)
		// 连续解决任务
		for i := 0; i < q; i++ {
			for j := 0; j < q; j++ {
				if i == j {
					continue
				}
				pos1, time1 := queries[i][0], queries[i][1]
				pos2, time2 := queries[j][0], queries[j][1]
				if time1+dist[pos1][pos2] <= time2 {
					dag[i] = append(dag[i], j)
				}
			}
		}

		res := MaxAntiChain(q, dag)
		fmt.Fprintln(out, len(res))
	}

	for {
		var n, m, q int
		fmt.Fscan(in, &n, &m, &q)
		if n+m+q == 0 {
			break
		}
		solve(n, m, q)
	}
}

// https://atcoder.jp/contests/abc237/tasks/abc237_h
// 给定一个字符串, 你需要从中选出若干回文子串, 并且使得选出的串不存在某一个是另一个的子串, 问最多能选出多少子串.
// n<=200
// 遍历所有回文子串,如果j是i的子串,则连边 i->j,求dag最长反链即可.
// 偏序包含关系(偏序关系最长链)
func Hakata() {
	zAlgo := func(s string) []int {
		n := len(s)
		if n == 0 {
			return nil
		}
		z := make([]int, n)
		j := 0
		for i := 1; i < n; i++ {
			var k int
			if j+z[j] <= i {
				k = 0
			} else {
				k = min(j+z[j]-i, z[i-j])
			}
			for i+k < n && s[k] == s[i+k] {
				k++
			}
			if j+z[j] < i+z[i] {
				j = i
			}
			z[i] = k
		}
		z[0] = n
		return z
	}

	// O(n+m)判断`shorter`是否是`longer`的子串.
	isSubstring := func(longer, shorter string) bool {
		if len(shorter) > len(longer) {
			return false
		}
		if len(shorter) == 0 {
			return true
		}
		n, m := len(longer), len(shorter)
		z := zAlgo(shorter + longer)
		for i := m; i < n+m; i++ {
			if z[i] >= m {
				return true
			}
		}
		return false
	}

	isPalindrome := func(s string) bool {
		n := len(s)
		for i := 0; i < n>>1; i++ {
			if s[i] != s[n-1-i] {
				return false
			}
		}
		return true
	}

	in, out := bufio.NewReader(os.Stdin), bufio.NewWriter(os.Stdout)
	defer out.Flush()

	var s string
	fmt.Fscan(in, &s)
	set := make(map[string]struct{})
	n := len(s)
	for start := 0; start < n; start++ {
		for end := start + 1; end <= n; end++ {
			cur := s[start:end]
			if isPalindrome(cur) {
				set[cur] = struct{}{}
			}
		}
	}
	allPalindromes := make([]string, 0, len(set))
	for k := range set {
		allPalindromes = append(allPalindromes, k)
	}

	dag := make([][]int, len(allPalindromes))
	for i := range dag {
		for j := range dag {
			if i == j {
				continue
			}
			if isSubstring(allPalindromes[i], allPalindromes[j]) {
				dag[i] = append(dag[i], j)
			}
		}
	}

	res := MaxAntiChain(len(dag), dag)
	fmt.Fprintln(out, len(res))
}

// https://yukicoder.me/problems/no/1479
// 给定一个矩阵, 你可以按照任意顺序执行以下操作任意多次:
// 选择矩阵的行。此时,将行中所有等于行元素最大值的元素全部变为0。
// 选择矩阵的列。此时,将列中所有等于列元素最大值的元素全部变为0。
// 你的目标是将矩阵的所有元素变为0。请求出达成目标所需的最小操作次数。
// ROW,COL<=500
// A[i][j]<=5e5
func Yuki1479() {
	in, out := bufio.NewReader(os.Stdin), bufio.NewWriter(os.Stdout)
	defer out.Flush()

	unique := func(a *[]int) {
		set := make(map[int]struct{})
		for _, v := range *a {
			set[v] = struct{}{}
		}
		allNums := make([]int, 0, len(set))
		for k := range set {
			allNums = append(allNums, k)
		}
		sort.Ints(allNums)
		*a = allNums
	}

	var ROW, COL int
	fmt.Fscan(in, &ROW, &COL)

	mp := make(map[int][][2]int)
	for i := 0; i < ROW; i++ {
		for j := 0; j < COL; j++ {
			var v int
			fmt.Fscan(in, &v)
			mp[v] = append(mp[v], [2]int{i, j})
		}
	}

	res := 0
	for k, points := range mp {
		if k == 0 {
			continue
		}
		xs, ys := make([]int, len(points)), make([]int, len(points))
		for i, p := range points {
			xs[i], ys[i] = p[0], p[1]
		}
		unique(&xs)
		unique(&ys)
		g := make([][]int, len(xs)+len(ys))
		for _, p := range points {
			x, y := p[0], p[1]
			x = sort.SearchInts(xs, x)
			y = sort.SearchInts(ys, y)
			g[x] = append(g[x], len(xs)+y)
		}
		bm := NewBipartiteMatching(len(g), g, nil)
		res += len(bm.MinVertexCover())
	}

	fmt.Fprintln(out, res)

}

const INF int = 1e18

// 二分图最大匹配.
type BipartiteMatching struct {
	n       int32
	graph   [][]int
	color   []int8
	dist    []int32
	match   []int32
	visited []bool
}

// colors: 如果为nil,内部会自动计算.
func NewBipartiteMatching(n int, graph [][]int, colors []int8) *BipartiteMatching {
	bm := &BipartiteMatching{
		n:       int32(n),
		graph:   graph,
		dist:    make([]int32, n),
		match:   make([]int32, n),
		visited: make([]bool, n),
	}
	if colors != nil {
		bm.color = colors
	} else {
		bm.color = BipartiteVertexColoring(n, graph)
	}
	if n > 0 && len(bm.color) == 0 {
		panic("not bipartite graph")
	}
	for i := range bm.dist {
		bm.dist[i] = -1
	}
	for i := range bm.match {
		bm.match[i] = -1
	}
	for {
		bm.bfs()
		for i := range bm.visited {
			bm.visited[i] = false
		}
		flow := 0
		for v := int32(0); v < bm.n; v++ {
			if bm.color[v] == 0 && bm.match[v] == -1 && bm.dfs(v) {
				flow++
			}
		}
		if flow == 0 {
			break
		}
	}
	return bm
}

// 最大匹配.
func (bm *BipartiteMatching) MaxMatching() (res [][2]int) {
	for v := int32(0); v < bm.n; v++ {
		if v < bm.match[v] {
			res = append(res, [2]int{int(v), int(bm.match[v])})
		}
	}
	return
}

// 最小点覆盖.
// 最小点覆盖是指在二部图中,可以覆盖所有边的最小顶点集合。
func (bm *BipartiteMatching) MinVertexCover() (res []int) {
	for v := int32(0); v < bm.n; v++ {
		if (bm.color[v] != 0) != (bm.dist[v] == -1) {
			res = append(res, int(v))
		}
	}
	return
}

// 最大独立集.
// 没有相邻顶点的最大顶点集合。
func (bm *BipartiteMatching) MaxIndependentSet() (res []int) {
	for v := int32(0); v < bm.n; v++ {
		if (bm.color[v] != 0) == (bm.dist[v] == -1) {
			res = append(res, int(v))
		}
	}
	return
}

// 最小边覆盖.返回排序后的边的编号.
// 可以覆盖所有顶点的最小边集合。
func (bm *BipartiteMatching) MinEdgeCover(edges [][2]int) (res []int) {
	done := make([]bool, bm.n)
	for ei, e := range edges {
		u, v := e[0], e[1]
		if done[u] || done[v] {
			continue
		}
		if bm.match[u] == int32(v) {
			res = append(res, ei)
			done[u] = true
			done[v] = true
		}
	}
	for ei, e := range edges {
		u, v := e[0], e[1]
		if !done[u] {
			res = append(res, ei)
			done[u] = true
		}
		if !done[v] {
			res = append(res, ei)
			done[v] = true
		}
	}
	sort.Ints(res)
	return
}

func (bm *BipartiteMatching) Debug() {
	fmt.Println("match", bm.match)
	fmt.Println("MinVertexCoverr", bm.MinVertexCover())
	fmt.Println("MaxIndependentSet", bm.MaxIndependentSet())
}

// Dulmage–Mendelsohn decomposition (DM分解)
// https://ei1333.github.io/library/graph/flow/bipartite-flow.hpp
// https://hitonanode.github.io/cplib-cpp/graph/dulmage_mendelsohn_decomposition.hpp.html
// 在残量网络的基础上添加虚拟源点和汇点,进行强连通分量分解.
// 性质:
//  1. 边是否存在与最大匹配中:
//     如果一条边的两个顶点所在的强连通分量相同,那么可以作为最大匹配的一条边(可能在最大匹配中)。
//     如果一条边的两个顶点所在的强连通分量相同并且没有其他边具有相同的id,那么它一定在任何最大匹配中。
//     如果一条边的两个顶点所在的强连通分量不同,那么不可能作为最大匹配的一条边。
//     如果一条边在某个最大匹配中,那么它一定在任何最大匹配中。
//  2. 点是否存在于最大匹配中:
//     如果一个顶点的颜色为 0,并且它的 id 值在 1 到 compCount 的闭区间范围内,那么这个顶点一定会被用于最大匹配。
//     如果一个顶点的颜色为 1,并且它的 id 值在 0 到 compCount-1 的闭区间范围内,那么这个顶点一定会被用于最大匹配。
//  3. 如果一条边从 color=0 的顶点到 color=1 的顶点,那么这条边的左顶点的 id 值应该小于或等于右顶点的 id 值。
func (bm *BipartiteMatching) DMDecomposition(edges [][2]int) (compCount int, belong []int) {
	belong = make([]int, bm.n)
	for i := range belong {
		belong[i] = -1
	}
	queue := []int{}
	add := func(v, x int) {
		if belong[v] == -1 {
			belong[v] = x
			queue = append(queue, v)
		}
	}
	for v := 0; v < int(bm.n); v++ {
		if bm.match[v] == -1 && bm.color[v] == 0 {
			add(v, 0)
		}
	}
	for v := 0; v < int(bm.n); v++ {
		if bm.match[v] == -1 && bm.color[v] == 1 {
			add(v, INF)
		}
	}
	for len(queue) > 0 {
		v := queue[0]
		queue = queue[1:]
		if bm.match[v] != -1 {
			add(int(bm.match[v]), belong[v])
		}
		if bm.color[v] == 0 && belong[v] == 0 {
			for _, to := range bm.graph[v] {
				add(to, belong[v])
			}
		}
		if bm.color[v] == 1 && belong[v] == INF {
			for _, to := range bm.graph[v] {
				add(to, belong[v])
			}
		}
	}

	// 残留图的强连通分量分解.
	vs := []int{}
	for v := 0; v < int(bm.n); v++ {
		if belong[v] == -1 {
			vs = append(vs, v)
		}
	}
	m := len(vs)
	dg := make([][]int, m)
	for i := range dg {
		v := vs[i]
		if bm.match[v] != -1 {
			j := sort.SearchInts(vs, int(bm.match[v]))
			dg[i] = append(dg[i], j)
		}
		if bm.color[v] == 0 {
			for _, to := range bm.graph[v] {
				if belong[to] != -1 || to == int(bm.match[v]) {
					continue
				}
				j := sort.SearchInts(vs, to)
				dg[i] = append(dg[i], j)
			}
		}
	}

	compCount, comp := StronglyConnectedComponent(len(dg), dg)
	compCount++

	for i := 0; i < m; i++ {
		belong[vs[i]] = 1 + comp[i]
	}
	for v := 0; v < int(bm.n); v++ {
		if belong[v] == INF {
			belong[v] = compCount
		}
	}
	return
}

func (bm *BipartiteMatching) bfs() {
	for i := range bm.dist {
		bm.dist[i] = -1
	}
	queue := []int32{}
	for v := int32(0); v < bm.n; v++ {
		if bm.color[v] == 0 && bm.match[v] == -1 {
			queue = append(queue, v)
			bm.dist[v] = 0
		}
	}
	for len(queue) > 0 {
		v := queue[0]
		queue = queue[1:]
		for _, to := range bm.graph[v] {
			bm.dist[to] = 0
			w := bm.match[to]
			if w != -1 && bm.dist[w] == -1 {
				bm.dist[w] = bm.dist[v] + 1
				queue = append(queue, w)
			}
		}
	}
}

func (bm *BipartiteMatching) dfs(v int32) bool {
	bm.visited[v] = true
	for _, to := range bm.graph[v] {
		w := bm.match[to]
		if w == -1 || (!bm.visited[w] && bm.dist[w] == bm.dist[v]+1 && bm.dfs(w)) {
			bm.match[to] = v
			bm.match[v] = int32(to)
			return true
		}
	}
	return false
}

// 无向图二分图着色.
// 如果不是二分图,返回空数组.
func BipartiteVertexColoring(n int, graph [][]int) (colors []int8) {
	uf := NewUf(2 * n)
	for cur, nexts := range graph {
		for _, next := range nexts {
			if cur < next {
				uf.Union(cur+n, next)
				uf.Union(cur, next+n)
			}
		}
	}
	colors = make([]int8, 2*n)
	for i := range colors {
		colors[i] = -1
	}
	for v := 0; v < n; v++ {
		if root := uf.Find(v); root == v && colors[root] < 0 {
			colors[root] = 0
			colors[uf.Find(v+n)] = 1
		}
	}
	for v := 0; v < n; v++ {
		colors[v] = colors[uf.Find(v)]
	}
	colors = colors[:n]
	for v := 0; v < n; v++ {
		if uf.Find(v) == uf.Find(v+n) {
			return nil
		}
	}
	return
}

type Uf struct {
	data []int
}

func NewUf(n int) *Uf {
	data := make([]int, n)
	for i := 0; i < n; i++ {
		data[i] = -1
	}
	return &Uf{data: data}
}

func (ufa *Uf) Union(key1, key2 int) bool {
	root1, root2 := ufa.Find(key1), ufa.Find(key2)
	if root1 == root2 {
		return false
	}
	if ufa.data[root1] > ufa.data[root2] {
		root1, root2 = root2, root1
	}
	ufa.data[root1] += ufa.data[root2]
	ufa.data[root2] = root1
	return true
}

func (ufa *Uf) Find(key int) int {
	if ufa.data[key] < 0 {
		return key
	}
	ufa.data[key] = ufa.Find(ufa.data[key])
	return ufa.data[key]
}

// 有向图强连通分量.
func StronglyConnectedComponent(n int, graph [][]int) (compCount int, belong []int) {
	n32 := int32(n)
	compId := int32(0)
	comp := make([]int32, n32)
	low := make([]int32, n32)
	ord := make([]int32, n32)
	for i := range ord {
		ord[i] = -1
	}
	path := []int32{}
	now := int32(0)

	var dfs func(int32)
	dfs = func(v int32) {
		low[v] = now
		ord[v] = now
		now++
		path = append(path, v)
		for _, to := range graph[v] {
			if ord[to] == -1 {
				dfs(int32(to))
				if low[v] > low[to] {
					low[v] = low[to]
				}
			} else if low[v] > ord[to] {
				low[v] = ord[to]
			}
		}
		if low[v] == ord[v] {
			for {
				u := path[len(path)-1]
				path = path[:len(path)-1]
				ord[u] = n32
				comp[u] = compId
				if u == v {
					break
				}
			}
			compId++
		}
	}

	for v := int32(0); v < n32; v++ {
		if ord[v] == -1 {
			dfs(v)
		}
	}

	compCount = int(compId)
	belong = make([]int, n)
	for v := 0; v < n; v++ {
		belong[v] = compCount - 1 - int(comp[v])
	}
	return
}

func SccDag(graph [][]int, compCount int, belong []int) (dag [][]int) {
	unique := func(nums []int32) []int32 {
		set := make(map[int32]struct{})
		for _, v := range nums {
			set[v] = struct{}{}
		}
		res := make([]int32, 0, len(set))
		for k := range set {
			res = append(res, k)
		}
		return res
	}

	edges := make([][]int32, compCount)
	for cur, nexts := range graph {
		curComp := belong[cur]
		for _, next := range nexts {
			nextComp := belong[next]
			if curComp != nextComp {
				edges[curComp] = append(edges[curComp], int32(nextComp))
			}
		}
	}

	dag = make([][]int, compCount)
	for cur := 0; cur < compCount; cur++ {
		edges[cur] = unique(edges[cur])
		for _, next := range edges[cur] {
			dag[cur] = append(dag[cur], int(next))
		}
	}

	return
}

// dag最长反链(最大独立集).
func MaxAntiChain(n int, dag [][]int) []int {
	newGraph := make([][]int, n+n)
	for i := 0; i < n; i++ {
		for _, to := range dag[i] {
			newGraph[i] = append(newGraph[i], to+n)
		}
	}
	bm := NewBipartiteMatching(n+n, newGraph, nil)
	cover := bm.MinVertexCover()
	ok := make([]bool, n)
	for i := range ok {
		ok[i] = true
	}
	for _, v := range cover {
		ok[v%n] = false
	}
	antichain := []int{}
	for v := 0; v < n; v++ {
		if ok[v] {
			antichain = append(antichain, v)
		}
	}
	return antichain
}

type Edge = [2]int

func Dijkstra(n int, adjList [][]Edge, start int) (dist, preV []int) {
	type pqItem struct{ node, dist int }
	dist = make([]int, n)
	for i := range dist {
		dist[i] = INF
	}
	dist[start] = 0
	preV = make([]int, n)
	for i := range preV {
		preV[i] = -1
	}

	pq := nhp(func(a, b H) int {
		return a.(pqItem).dist - b.(pqItem).dist
	}, nil)
	pq.Push(pqItem{start, 0})

	for pq.Len() > 0 {
		curNode := pq.Pop().(pqItem)
		cur, curDist := curNode.node, curNode.dist
		if curDist > dist[cur] {
			continue
		}

		for _, edge := range adjList[cur] {
			next, weight := edge[0], edge[1]
			if cand := curDist + weight; cand < dist[next] {
				dist[next] = cand
				preV[next] = cur
				pq.Push(pqItem{next, cand})
			}
		}
	}

	return
}

type H = interface{}

// Should return a number:
//
//	negative , if a < b
//	zero     , if a == b
//	positive , if a > b
type Comparator func(a, b H) int

func nhp(comparator Comparator, nums []H) *Heap {
	nums = append(nums[:0:0], nums...)
	heap := &Heap{comparator: comparator, data: nums}
	heap.heapify()
	return heap
}

type Heap struct {
	data       []H
	comparator Comparator
}

func (h *Heap) Push(value H) {
	h.data = append(h.data, value)
	h.pushUp(h.Len() - 1)
}

func (h *Heap) Pop() (value H) {
	if h.Len() == 0 {
		return
	}

	value = h.data[0]
	h.data[0] = h.data[h.Len()-1]
	h.data = h.data[:h.Len()-1]
	h.pushDown(0)
	return
}

func (h *Heap) Peek() (value H) {
	if h.Len() == 0 {
		return
	}
	value = h.data[0]
	return
}

func (h *Heap) Len() int { return len(h.data) }

func (h *Heap) heapify() {
	n := h.Len()
	for i := (n >> 1) - 1; i > -1; i-- {
		h.pushDown(i)
	}
}

func (h *Heap) pushUp(root int) {
	for parent := (root - 1) >> 1; parent >= 0 && h.comparator(h.data[root], h.data[parent]) < 0; parent = (root - 1) >> 1 {
		h.data[root], h.data[parent] = h.data[parent], h.data[root]
		root = parent
	}
}

func (h *Heap) pushDown(root int) {
	n := h.Len()
	for left := (root<<1 + 1); left < n; left = (root<<1 + 1) {
		right := left + 1
		minIndex := root

		if h.comparator(h.data[left], h.data[minIndex]) < 0 {
			minIndex = left
		}

		if right < n && h.comparator(h.data[right], h.data[minIndex]) < 0 {
			minIndex = right
		}

		if minIndex == root {
			return
		}

		h.data[root], h.data[minIndex] = h.data[minIndex], h.data[root]
		root = minIndex
	}
}

func min(a, b int) int {
	if a <= b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a >= b {
		return a
	}
	return b
}
0