docs: @Override
    public DoubleDBIDList reverseKNNQuery(DBIDRef id, int k) {
      ModifiableDoubleDBIDList result = DBIDUtil.newDistanceDBIDList();
      final Heap<MTreeSearchCandidate> pq = new UpdatableHeap<>();
  
      // push root
      pq.add(new MTreeSearchCandidate(0., getRootID(), null, Double.NaN));
  
      // search in tree
      while(!pq.isEmpty()) {
        MTreeSearchCandidate pqNode = pq.poll();
        // FIXME: cache the distance to the routing object in the queue node!
  
        MkAppTreeNode<O> node = getNode(pqNode.nodeID);
  
        // directory node
        if(!node.isLeaf()) {
          for(int i = 0; i < node.getNumEntries(); i++) {
            MkAppEntry entry = node.getEntry(i);
            double distance = distance(entry.getRoutingObjectID(), id);
            double minDist = (entry.getCoveringRadius() > distance) ? 0. : distance - entry.getCoveringRadius();
  
            double approxValue = settings.log ? FastMath.exp(entry.approximatedValueAt(k)) : entry.approximatedValueAt(k);
            if(approxValue < 0) {
              approxValue = 0;
            }
  
            if(minDist <= approxValue) {
              pq.add(new MTreeSearchCandidate(minDist, getPageID(entry), entry.getRoutingObjectID(), Double.NaN));
            }
          }
        }
        // data node
        else {
          for(int i = 0; i < node.getNumEntries(); i++) {
            MkAppLeafEntry entry = (MkAppLeafEntry) node.getEntry(i);
            double distance = distance(entry.getRoutingObjectID(), id);
            double approxValue = settings.log ? FastMath.exp(entry.approximatedValueAt(k)) : entry.approximatedValueAt(k);
            if(approxValue < 0) {
              approxValue = 0;
            }
  
            if(distance <= approxValue) {
              result.add(distance, entry.getRoutingObjectID());
            }
          }
        }
      }
      return result;
    }