Skip to content

point_set_range_freq.hpp

SECTIONData Structure INCLUDEnoya/point_set_range_freq.hpp

维护数组的单点赋值,并统计区间内某个值的出现次数;适合动态序列上的区间频率查询。

Complexity: Time: Expected O(n log n) build and O(log n) assignment/frequency query. Space: O(n).

AC 记录:point_set_range_frequency

跳到代码 · GitHub ↗

Implementation

当前头文件,省略 include guard;依赖见 #include

/// @complexity Time: Expected O(n log n) build and O(log n) assignment/frequency query.
/// Space: O(n).

#include <cassert>
#include <cstdint>
#include <map>
#include <random>
#include <utility>
#include <vector>

namespace noya {

/// @brief Point assignment and exact-value frequency queries on half-open
/// ranges, both in expected O(log n) time.
template <class T> struct point_set_range_frequency {
  struct node {
    int ls = -1;
    int rs = -1;
    int sz = 1;
    std::uint64_t rnd = 0;
  };

  int n = 0;
  std::vector<T> a;
  std::vector<node> tr;
  std::map<T, int> rt;

  point_set_range_frequency() = default;

  explicit point_set_range_frequency(
      const std::vector<T> &arr, std::uint64_t rng = 0x243f6a8885a308d3ULL) {
    build(arr, rng);
  }

  /// @brief Rebuild the index from input in expected O(n log n) time.
  void build(const std::vector<T> &arr,
             std::uint64_t rng = 0x243f6a8885a308d3ULL) {
    n = int(arr.size());
    a = arr;
    tr.assign(n, {});
    rt.clear();
    std::mt19937_64 rd(rng);
    for (int idx = 0; idx < n; idx++) {
      tr[idx].rnd = rd();
      auto [it, ok] = rt.try_emplace(a[idx], -1);
      it->second = insert(it->second, idx);
    }
  }

  /// @brief Assign value to position index in expected O(log n) time.
  void set(int idx, const T &val) {
    assert(0 <= idx && idx < n);
    if (a[idx] == val) {
      return;
    }

    auto oit = rt.find(a[idx]);
    assert(oit != rt.end());
    oit->second = erase(oit->second, idx);
    if (oit->second == -1) {
      rt.erase(oit);
    }

    tr[idx].ls = tr[idx].rs = -1;
    tr[idx].sz = 1;
    auto [nit, ok] = rt.try_emplace(val, -1);
    nit->second = insert(nit->second, idx);
    a[idx] = val;
  }

  /// @brief Count occurrences of value in [l, r) in expected O(log n)
  /// time.
  int query(int l, int r, const T &val) const {
    assert(0 <= l && l <= r && r <= n);
    auto it = rt.find(val);
    if (it == rt.end()) {
      return 0;
    }
    return count_less(it->second, r) - count_less(it->second, l);
  }

  /// @brief Return the current value at one position.
  const T &get(int idx) const {
    assert(0 <= idx && idx < n);
    return a[idx];
  }

private:
  int subtree_size(int rt0) const { return rt0 == -1 ? 0 : tr[rt0].sz; }

  void pull(int rt0) {
    tr[rt0].sz = 1 + subtree_size(tr[rt0].ls) + subtree_size(tr[rt0].rs);
  }

  bool higher_priority(int A, int b) const {
    return tr[A].rnd != tr[b].rnd ? tr[A].rnd > tr[b].rnd : A < b;
  }

  std::pair<int, int> split(int rt0, int key) {
    if (rt0 == -1) {
      return {-1, -1};
    }
    if (rt0 < key) {
      auto [l, r] = split(tr[rt0].rs, key);
      tr[rt0].rs = l;
      pull(rt0);
      return {rt0, r};
    }
    auto [l, r] = split(tr[rt0].ls, key);
    tr[rt0].ls = r;
    pull(rt0);
    return {l, rt0};
  }

  int merge(int l, int r) {
    if (l == -1) {
      return r;
    }
    if (r == -1) {
      return l;
    }
    if (higher_priority(l, r)) {
      tr[l].rs = merge(tr[l].rs, r);
      pull(l);
      return l;
    }
    tr[r].ls = merge(l, tr[r].ls);
    pull(r);
    return r;
  }

  int insert(int rt0, int idx) {
    if (rt0 == -1) {
      return idx;
    }
    if (higher_priority(idx, rt0)) {
      auto [l, r] = split(rt0, idx);
      tr[idx].ls = l;
      tr[idx].rs = r;
      pull(idx);
      return idx;
    }
    if (idx < rt0) {
      tr[rt0].ls = insert(tr[rt0].ls, idx);
    } else {
      tr[rt0].rs = insert(tr[rt0].rs, idx);
    }
    pull(rt0);
    return rt0;
  }

  int erase(int rt0, int idx) {
    assert(rt0 != -1);
    if (rt0 == idx) {
      return merge(tr[rt0].ls, tr[rt0].rs);
    }
    if (idx < rt0) {
      tr[rt0].ls = erase(tr[rt0].ls, idx);
    } else {
      tr[rt0].rs = erase(tr[rt0].rs, idx);
    }
    pull(rt0);
    return rt0;
  }

  int count_less(int rt0, int key) const {
    int res = 0;
    while (rt0 != -1) {
      if (rt0 < key) {
        res += 1 + subtree_size(tr[rt0].ls);
        rt0 = tr[rt0].rs;
      } else {
        rt0 = tr[rt0].ls;
      }
    }
    return res;
  }
};

} // namespace noya
#ifndef NOYA_POINT_SET_RANGE_FREQUENCY_HPP
#define NOYA_POINT_SET_RANGE_FREQUENCY_HPP 1

/// @complexity Time: Expected O(n log n) build and O(log n) assignment/frequency query.
/// Space: O(n).

#include <cassert>
#include <cstdint>
#include <map>
#include <random>
#include <utility>
#include <vector>

namespace noya {

/// @brief Point assignment and exact-value frequency queries on half-open
/// ranges, both in expected O(log n) time.
template <class T> struct point_set_range_frequency {
  struct node {
    int ls = -1;
    int rs = -1;
    int sz = 1;
    std::uint64_t rnd = 0;
  };

  int n = 0;
  std::vector<T> a;
  std::vector<node> tr;
  std::map<T, int> rt;

  point_set_range_frequency() = default;

  explicit point_set_range_frequency(
      const std::vector<T> &arr, std::uint64_t rng = 0x243f6a8885a308d3ULL) {
    build(arr, rng);
  }

  /// @brief Rebuild the index from input in expected O(n log n) time.
  void build(const std::vector<T> &arr,
             std::uint64_t rng = 0x243f6a8885a308d3ULL) {
    n = int(arr.size());
    a = arr;
    tr.assign(n, {});
    rt.clear();
    std::mt19937_64 rd(rng);
    for (int idx = 0; idx < n; idx++) {
      tr[idx].rnd = rd();
      auto [it, ok] = rt.try_emplace(a[idx], -1);
      it->second = insert(it->second, idx);
    }
  }

  /// @brief Assign value to position index in expected O(log n) time.
  void set(int idx, const T &val) {
    assert(0 <= idx && idx < n);
    if (a[idx] == val) {
      return;
    }

    auto oit = rt.find(a[idx]);
    assert(oit != rt.end());
    oit->second = erase(oit->second, idx);
    if (oit->second == -1) {
      rt.erase(oit);
    }

    tr[idx].ls = tr[idx].rs = -1;
    tr[idx].sz = 1;
    auto [nit, ok] = rt.try_emplace(val, -1);
    nit->second = insert(nit->second, idx);
    a[idx] = val;
  }

  /// @brief Count occurrences of value in [l, r) in expected O(log n)
  /// time.
  int query(int l, int r, const T &val) const {
    assert(0 <= l && l <= r && r <= n);
    auto it = rt.find(val);
    if (it == rt.end()) {
      return 0;
    }
    return count_less(it->second, r) - count_less(it->second, l);
  }

  /// @brief Return the current value at one position.
  const T &get(int idx) const {
    assert(0 <= idx && idx < n);
    return a[idx];
  }

private:
  int subtree_size(int rt0) const { return rt0 == -1 ? 0 : tr[rt0].sz; }

  void pull(int rt0) {
    tr[rt0].sz = 1 + subtree_size(tr[rt0].ls) + subtree_size(tr[rt0].rs);
  }

  bool higher_priority(int A, int b) const {
    return tr[A].rnd != tr[b].rnd ? tr[A].rnd > tr[b].rnd : A < b;
  }

  std::pair<int, int> split(int rt0, int key) {
    if (rt0 == -1) {
      return {-1, -1};
    }
    if (rt0 < key) {
      auto [l, r] = split(tr[rt0].rs, key);
      tr[rt0].rs = l;
      pull(rt0);
      return {rt0, r};
    }
    auto [l, r] = split(tr[rt0].ls, key);
    tr[rt0].ls = r;
    pull(rt0);
    return {l, rt0};
  }

  int merge(int l, int r) {
    if (l == -1) {
      return r;
    }
    if (r == -1) {
      return l;
    }
    if (higher_priority(l, r)) {
      tr[l].rs = merge(tr[l].rs, r);
      pull(l);
      return l;
    }
    tr[r].ls = merge(l, tr[r].ls);
    pull(r);
    return r;
  }

  int insert(int rt0, int idx) {
    if (rt0 == -1) {
      return idx;
    }
    if (higher_priority(idx, rt0)) {
      auto [l, r] = split(rt0, idx);
      tr[idx].ls = l;
      tr[idx].rs = r;
      pull(idx);
      return idx;
    }
    if (idx < rt0) {
      tr[rt0].ls = insert(tr[rt0].ls, idx);
    } else {
      tr[rt0].rs = insert(tr[rt0].rs, idx);
    }
    pull(rt0);
    return rt0;
  }

  int erase(int rt0, int idx) {
    assert(rt0 != -1);
    if (rt0 == idx) {
      return merge(tr[rt0].ls, tr[rt0].rs);
    }
    if (idx < rt0) {
      tr[rt0].ls = erase(tr[rt0].ls, idx);
    } else {
      tr[rt0].rs = erase(tr[rt0].rs, idx);
    }
    pull(rt0);
    return rt0;
  }

  int count_less(int rt0, int key) const {
    int res = 0;
    while (rt0 != -1) {
      if (rt0 < key) {
        res += 1 + subtree_size(tr[rt0].ls);
        rt0 = tr[rt0].rs;
      } else {
        rt0 = tr[rt0].ls;
      }
    }
    return res;
  }
};

} // namespace noya

#endif // NOYA_POINT_SET_RANGE_FREQUENCY_HPP
#include <cassert>
#include <cstdint>
#include <map>
#include <random>
#include <utility>
#include <vector>

/// @complexity Time: Expected O(n log n) build and O(log n) assignment/frequency query.
/// Space: O(n).

namespace noya {

/// @brief Point assignment and exact-value frequency queries on half-open
/// ranges, both in expected O(log n) time.
template <class T> struct point_set_range_frequency {
  struct node {
    int ls = -1;
    int rs = -1;
    int sz = 1;
    std::uint64_t rnd = 0;
  };

  int n = 0;
  std::vector<T> a;
  std::vector<node> tr;
  std::map<T, int> rt;

  point_set_range_frequency() = default;

  explicit point_set_range_frequency(
      const std::vector<T> &arr, std::uint64_t rng = 0x243f6a8885a308d3ULL) {
    build(arr, rng);
  }

  /// @brief Rebuild the index from input in expected O(n log n) time.
  void build(const std::vector<T> &arr,
             std::uint64_t rng = 0x243f6a8885a308d3ULL) {
    n = int(arr.size());
    a = arr;
    tr.assign(n, {});
    rt.clear();
    std::mt19937_64 rd(rng);
    for (int idx = 0; idx < n; idx++) {
      tr[idx].rnd = rd();
      auto [it, ok] = rt.try_emplace(a[idx], -1);
      it->second = insert(it->second, idx);
    }
  }

  /// @brief Assign value to position index in expected O(log n) time.
  void set(int idx, const T &val) {
    assert(0 <= idx && idx < n);
    if (a[idx] == val) {
      return;
    }

    auto oit = rt.find(a[idx]);
    assert(oit != rt.end());
    oit->second = erase(oit->second, idx);
    if (oit->second == -1) {
      rt.erase(oit);
    }

    tr[idx].ls = tr[idx].rs = -1;
    tr[idx].sz = 1;
    auto [nit, ok] = rt.try_emplace(val, -1);
    nit->second = insert(nit->second, idx);
    a[idx] = val;
  }

  /// @brief Count occurrences of value in [l, r) in expected O(log n)
  /// time.
  int query(int l, int r, const T &val) const {
    assert(0 <= l && l <= r && r <= n);
    auto it = rt.find(val);
    if (it == rt.end()) {
      return 0;
    }
    return count_less(it->second, r) - count_less(it->second, l);
  }

  /// @brief Return the current value at one position.
  const T &get(int idx) const {
    assert(0 <= idx && idx < n);
    return a[idx];
  }

private:
  int subtree_size(int rt0) const { return rt0 == -1 ? 0 : tr[rt0].sz; }

  void pull(int rt0) {
    tr[rt0].sz = 1 + subtree_size(tr[rt0].ls) + subtree_size(tr[rt0].rs);
  }

  bool higher_priority(int A, int b) const {
    return tr[A].rnd != tr[b].rnd ? tr[A].rnd > tr[b].rnd : A < b;
  }

  std::pair<int, int> split(int rt0, int key) {
    if (rt0 == -1) {
      return {-1, -1};
    }
    if (rt0 < key) {
      auto [l, r] = split(tr[rt0].rs, key);
      tr[rt0].rs = l;
      pull(rt0);
      return {rt0, r};
    }
    auto [l, r] = split(tr[rt0].ls, key);
    tr[rt0].ls = r;
    pull(rt0);
    return {l, rt0};
  }

  int merge(int l, int r) {
    if (l == -1) {
      return r;
    }
    if (r == -1) {
      return l;
    }
    if (higher_priority(l, r)) {
      tr[l].rs = merge(tr[l].rs, r);
      pull(l);
      return l;
    }
    tr[r].ls = merge(l, tr[r].ls);
    pull(r);
    return r;
  }

  int insert(int rt0, int idx) {
    if (rt0 == -1) {
      return idx;
    }
    if (higher_priority(idx, rt0)) {
      auto [l, r] = split(rt0, idx);
      tr[idx].ls = l;
      tr[idx].rs = r;
      pull(idx);
      return idx;
    }
    if (idx < rt0) {
      tr[rt0].ls = insert(tr[rt0].ls, idx);
    } else {
      tr[rt0].rs = insert(tr[rt0].rs, idx);
    }
    pull(rt0);
    return rt0;
  }

  int erase(int rt0, int idx) {
    assert(rt0 != -1);
    if (rt0 == idx) {
      return merge(tr[rt0].ls, tr[rt0].rs);
    }
    if (idx < rt0) {
      tr[rt0].ls = erase(tr[rt0].ls, idx);
    } else {
      tr[rt0].rs = erase(tr[rt0].rs, idx);
    }
    pull(rt0);
    return rt0;
  }

  int count_less(int rt0, int key) const {
    int res = 0;
    while (rt0 != -1) {
      if (rt0 < key) {
        res += 1 + subtree_size(tr[rt0].ls);
        rt0 = tr[rt0].rs;
      } else {
        rt0 = tr[rt0].ls;
      }
    }
    return res;
  }
};

} // namespace noya