Skip to the content.

:heavy_check_mark: Static Point Add Rectangle Sum
(data-structure/static-point-add-rectangle-sum.hpp)

点への加算と長方形内の総和を offline で処理する.

StaticPointAddRectangleSum<T, I> として使う.座標の型 I の既定値は int,値の型 T は加減算が可能な型とする.長方形は半開領域 $[lx,rx)\times[ly,ry)$ で表す.

点とクエリの総数を $N$ として,calc() は $O(N\log N)$ 時間,$O(N)$ 空間.$x$ 座標順に走査し,$y$ 座標を Binary Indexed Tree で管理する.

資料

Depends on

Verified with

Code

#pragma once

#include "data-structure/binary-indexed-tree.hpp"

template <class T, class I = int>
struct StaticPointAddRectangleSum {
  void query_add(I x, I y, T v) { ps.push_back({x, y, v}); }
  void query_sum(I lx, I rx, I ly, I ry) {
    assert(lx <= rx && ly <= ry);
    qs.push_back({lx, rx, ly, ry});
  }
  vector<T> calc() const {
    struct E {
      I x, ly, ry;
      int q, s;
      bool operator<(const E& e) const { return x < e.x; }
    };
    vector<I> ys;
    ys.reserve(ps.size());
    for (auto [x, y, v] : ps) ys.push_back(y);
    sort(ys.begin(), ys.end());
    ys.erase(unique(ys.begin(), ys.end()), ys.end());
    vector<P> a = ps;
    sort(a.begin(), a.end(), [](const P& p, const P& q) { return p.x < q.x; });
    vector<E> ev;
    ev.reserve(qs.size() * 2);
    for (int i = 0; i < (int)qs.size(); i++) {
      auto [lx, rx, ly, ry] = qs[i];
      ev.push_back({lx, ly, ry, i, -1});
      ev.push_back({rx, ly, ry, i, 1});
    }
    sort(ev.begin(), ev.end());
    BinaryIndexedTree<T> bit(ys.size());
    vector<T> ans(qs.size());
    int p = 0;
    for (auto [x, ly, ry, q, s] : ev) {
      while (p < (int)a.size() && a[p].x < x) {
        bit.add(LB(ys, a[p].y), a[p].v);
        p++;
      }
      T v = bit.sum(LB(ys, ly), LB(ys, ry));
      ans[q] += s == 1 ? v : -v;
    }
    return ans;
  }

 private:
  struct P {
    I x, y;
    T v;
  };
  struct Q {
    I lx, rx, ly, ry;
  };
  vector<P> ps;
  vector<Q> qs;
};

/**
 * @brief Static Point Add Rectangle Sum
 * @docs docs/data-structure/static-point-add-rectangle-sum.md
 */
#line 2 "data-structure/static-point-add-rectangle-sum.hpp"

#line 2 "data-structure/binary-indexed-tree.hpp"

template <class T>
struct BinaryIndexedTree {
  int size;
  vector<T> data;
  BinaryIndexedTree(int n) : size(n), data(n) {}
  void add(int p, T x) {
    for (p++; p <= size; p += p & -p) data[p - 1] += x;
  }
  T sum(int p) {
    T s = 0;
    for (; p; p -= p & -p) s += data[p - 1];
    return s;
  }
  T sum(int l, int r) { return sum(r) - sum(l); }

  template <bool (*f)(T)>
  int lower_bound() const {
    return lower_bound([](T x) { return f(x); });
  }
  template <class F>
  int lower_bound(F f) const {
    if (f(T(0))) return 0;
    int x = 0, r = 1;
    while (r < size) r = r << 1;
    T s = 0;
    for (int len = r; len > 0; len >>= 1) {
      if (x + len < size && !f(s + data[x + len]))
        s += data[x += len];
    }
    return x + 1;
  }
};

/**
 * @brief Binary Indexed Tree
 * @docs docs/data-structure/binary-indexed-tree.md
 */
#line 4 "data-structure/static-point-add-rectangle-sum.hpp"

template <class T, class I = int>
struct StaticPointAddRectangleSum {
  void query_add(I x, I y, T v) { ps.push_back({x, y, v}); }
  void query_sum(I lx, I rx, I ly, I ry) {
    assert(lx <= rx && ly <= ry);
    qs.push_back({lx, rx, ly, ry});
  }
  vector<T> calc() const {
    struct E {
      I x, ly, ry;
      int q, s;
      bool operator<(const E& e) const { return x < e.x; }
    };
    vector<I> ys;
    ys.reserve(ps.size());
    for (auto [x, y, v] : ps) ys.push_back(y);
    sort(ys.begin(), ys.end());
    ys.erase(unique(ys.begin(), ys.end()), ys.end());
    vector<P> a = ps;
    sort(a.begin(), a.end(), [](const P& p, const P& q) { return p.x < q.x; });
    vector<E> ev;
    ev.reserve(qs.size() * 2);
    for (int i = 0; i < (int)qs.size(); i++) {
      auto [lx, rx, ly, ry] = qs[i];
      ev.push_back({lx, ly, ry, i, -1});
      ev.push_back({rx, ly, ry, i, 1});
    }
    sort(ev.begin(), ev.end());
    BinaryIndexedTree<T> bit(ys.size());
    vector<T> ans(qs.size());
    int p = 0;
    for (auto [x, ly, ry, q, s] : ev) {
      while (p < (int)a.size() && a[p].x < x) {
        bit.add(LB(ys, a[p].y), a[p].v);
        p++;
      }
      T v = bit.sum(LB(ys, ly), LB(ys, ry));
      ans[q] += s == 1 ? v : -v;
    }
    return ans;
  }

 private:
  struct P {
    I x, y;
    T v;
  };
  struct Q {
    I lx, rx, ly, ry;
  };
  vector<P> ps;
  vector<Q> qs;
};

/**
 * @brief Static Point Add Rectangle Sum
 * @docs docs/data-structure/static-point-add-rectangle-sum.md
 */
Back to top page