Spaghetti Source logo

区間木

説明

区間木は一次元の点位置決定問題に答える静的なデータ構造である.具体的には以下のことが行える.

以下の実装は点クエリについてのみである.

区間木の本来の形は静的に固定された座標の上で自由に insert / erase が行えるデータ構造だが,erase は実装していない.insert と同じコードで insert されたであろう場所を手繰り,そこで erase をかければできるが.

計算量

使い方

ソースコード

typedef int position;
typedef int contents;
struct interval {
  position low, high;
  interval(position low, position high) :
    low(low), high(high) { }
};

struct interval_tree {
  vector<position> pos;
  struct node {
    vector<contents> values;
    position B, E, M;
    node *left, *right;
  } *root;

  template <class IN>
  interval_tree(IN begin, IN end) : pos(begin, end) {
    root = build_tree(0, pos.size()-1);
  }
  ~interval_tree() { release(root); }

  node *build_tree(int i, int j) {
    int m = (i+j)/2;
    node *t = new node;
    t->B = pos[i]; t->E = pos[j]; t->M = pos[m];
    t->left  = (i+1 < j ? build_tree(i, m) : NULL);
    t->right = (i+1 < j ? build_tree(m, j) : NULL);
    return t;
  }
  void insert(const interval& I, contents c) { insert(root, I, c); }
  void insert(node *v, const interval& I, contents c) {
    if (I.low <= v->B && v->E <= I.high) {
      v->values.push_back( c );
    } else {
      if (I.low  < v->M) insert(v->left , I, c);
      if (I.high > v->M) insert(v->right, I, c);
    }
  }
  template <class OUT>
  void query(position p, OUT out) { query(root, p, out); }
  template <class OUT>
  void query(node *t, position p, OUT out) {
    if (!t || p < t->B || p >= t->E) return;
    copy(t->values.begin(), t->values.end(), out);
    if (p < t->M) query(t->left, p, out);   // 半開区間の探索になる
    else          query(t->right, p, out);
  }
  void release(node *t) {
    if (t->left) release(t->left);
    if (t->right) release(t->right);
    delete t;
  }
};

Verified

前原 貴憲(maehara@prefield.com).

Last Modified: 2006.12.11 08:43:07.