docs: private void dfs() {
      Deque<Node> stack = new LinkedList<>();
      stack.add(tree.getRootNode());
      while (!stack.isEmpty()) {
        Node node = stack.removeLast();
        node.startSize = list.size();
        if (node.getEdges().isEmpty()) {
          // leaf
          list.add(node.depth);
          node.endSize = list.size();
        } else {
          if (!node.equals(tree.getRootNode())) {
            // inner node = not leaf and not root
            innerNodes.add(node);
          }
          for (Edge edge : node.getEdges()) {
            Node endNode = edge.getEndNode();
            endNode.depth = node.depth + edge.getSpan() + 1;
            stack.addLast(endNode);
          }
        }
      }
      // At this point all inner nodes are ordered by the time of entering, so we visit them from last to first
      ListIterator<Node> iterator = innerNodes.listIterator(innerNodes.size());
      while (iterator.hasPrevious()) {
        Node node = iterator.previous();
        int max = -1;
        for (Edge edge : node.getEdges()) {
          max = Math.max(edge.getEndNode().endSize, max);
        }
        node.endSize = max;
      }
    }