#import "@preview/cetz:0.3.1": canvas, draw

#let leetcode-tree(nodes, highlighted: ()) = {
  let height = calc.ceil(
    calc.log(
      nodes.len() + 1,
      base: 2
    )
  )

  let dy = 1
  let dx = 0.8
  let r = 0.3
  let width = dx * (calc.pow(2, height - 1) + 1)
  
  for lvl in range(height) {
    let n = calc.pow(2, lvl)
    let y = -lvl * dy
    
    for i in range(n) {
      let j = i + n - 1
      if j >= nodes.len() {
        break
      }

      let node = nodes.at(j)
      if node != none {
        let x = width * (i + .5) / n
        let name = "l" + str(lvl) + "-n" + str(i)
        let is-highlighted = (j in highlighted) or (lvl, i) in highlighted
        draw.circle(
          (x, y),
          radius: r,
          name: name,
          fill: if is-highlighted {
            blue.lighten(75%)
          } else {
            none
          }
        )
        draw.content(
          name + ".center",
          str(node)
        )

        if lvl != 0 {
          let pi = i.bit-rshift(1)
          draw.line(
            "l" + str(lvl - 1) + "-n" + str(pi),
            name
          )
        }
      }
    }
  }
}

#set page(width: auto, height: auto, margin: 1cm)

#canvas({
  leetcode-tree(
    (2,1,3,none,none,none,4),
    highlighted: (2,)
  )
})

#pagebreak()

#canvas({
  leetcode-tree(
    (1,2,3,4,5,6,none,none,none,7,8)
  )
})

#pagebreak()

#canvas({
  leetcode-tree(
    (99,3,2,none,6,4,5,none,none,none,none,8,7)
  )
})

#pagebreak()

#canvas({
  leetcode-tree(
    (0,3,1,none,none,none,2)
  )
})

#pagebreak()

#canvas({
  leetcode-tree(
    (0,3,1,2)
  )
})