二次元セグメント木
(data-structure-2d/2d-segment-tree.hpp)
- View this file on GitHub
- Last update: 2023-09-08 22:52:34+09:00
- Include:
#include "data-structure-2d/2d-segment-tree.hpp"
二次元セグメント木
概要
二次元セグメント木とは、二次元配列上において非可換なモノイドに関する演算を計算するときに使用できるデータ構造である。
大きさ $H \times W$ の二次元配列に対して
- 要素の一点更新
- 二次元領域の総積の取得
を $\mathrm{O}(\log H \log W)$ で行うことができる。
使い方
- テンプレート引数
T
: データの型。 - テンプレート引数
F
: モノイドを計算する関数の型。 -
SegmentTree2D(h, w, _f, const T& i)
: コンストラクタ。h,w
は配列の縦横のサイズ、_f
はモノイドを計算する関数、i
はモノイドの単位元が載る。時間・空間ともに $\mathrm{O}(hw)$ -
void init(h, w)
: サイズを $h \times w$ に、要素を単位元 $I$ に初期化する。$\mathrm{O}(hw)$ -
void set(h, w, x)
: 配列を $A$ として $A_{h,w}$ の値を更新する。build
より前に呼ぶ必要がある。 $\mathrm{O}(1)$ -
void build()
: データ構造を構築する。$\mathrm{O}(hw)$ -
T& get(h, w)
,operator()(h, w)
: $A_{h,w}$ の値を取得する。 $\mathrm{O}(1)$ -
void update(h, w, x)
: 配列を $A$ として $A_{h,w}$ の値を更新する。いつでも呼ぶことができる。 $\mathrm{O}(\log H \log W)$ -
void query(h1, w1, h2, w2)
: 区間 $[A_{h_1,w_1}, A_{h2, w2})$ の総積を取得する。$\mathrm{O}(\log H \log W)$
Verified with
Code
#pragma once
template <typename T, typename F>
struct SegmentTree2D {
private:
int id(int h, int w) const { return h * 2 * W + w; }
public:
int H, W;
vector<T> seg;
const F f;
const T I;
SegmentTree2D(int h, int w, F _f, const T& i) : f(_f), I(i) { init(h, w); }
void init(int h, int w) {
H = W = 1;
while (H < h) H <<= 1;
while (W < w) W <<= 1;
seg.assign(4 * H * W, I);
}
// build にのみ呼ぶ
void set(int h, int w, const T& x) { seg[id(h + H, w + W)] = x; }
void build() {
// w in [W, 2W)
for (int w = W; w < 2 * W; w++) {
for (int h = H - 1; h; h--) {
seg[id(h, w)] = f(seg[id(2 * h + 0, w)], seg[id(2 * h + 1, w)]);
}
}
// h in [0, 2H)
for (int h = 0; h < 2 * H; h++) {
for (int w = W - 1; w; w--) {
seg[id(h, w)] = f(seg[id(h, 2 * w + 0)], seg[id(h, 2 * w + 1)]);
}
}
}
T get(int h, int w) const { return seg[id(h + H, w + W)]; }
T operator()(int h, int w) const { return seg[id(h + H, w + W)]; }
void update(int h, int w, const T& x) {
h += H, w += W;
seg[id(h, w)] = x;
for (int i = h >> 1; i; i >>= 1) {
seg[id(i, w)] = f(seg[id(2 * i + 0, w)], seg[id(2 * i + 1, w)]);
}
for (; h; h >>= 1) {
for (int j = w >> 1; j; j >>= 1) {
seg[id(h, j)] = f(seg[id(h, 2 * j + 0)], seg[id(h, 2 * j + 1)]);
}
}
}
T _inner_query(int h, int w1, int w2) {
T res = I;
for (; w1 < w2; w1 >>= 1, w2 >>= 1) {
if (w1 & 1) res = f(res, seg[id(h, w1)]), w1++;
if (w2 & 1) --w2, res = f(res, seg[id(h, w2)]);
}
return res;
}
// [ (h1,w1), (h2,w2) ) 半開
T query(int h1, int w1, int h2, int w2) {
if (h1 >= h2 || w1 >= w2) return I;
T res = I;
h1 += H, h2 += H, w1 += W, w2 += W;
for (; h1 < h2; h1 >>= 1, h2 >>= 1) {
if (h1 & 1) res = f(res, _inner_query(h1, w1, w2)), h1++;
if (h2 & 1) --h2, res = f(res, _inner_query(h2, w1, w2));
}
return res;
}
};
/**
* @brief 二次元セグメント木
* @docs docs/data-structure-2d/2d-segment-tree.md
*/
#line 2 "data-structure-2d/2d-segment-tree.hpp"
template <typename T, typename F>
struct SegmentTree2D {
private:
int id(int h, int w) const { return h * 2 * W + w; }
public:
int H, W;
vector<T> seg;
const F f;
const T I;
SegmentTree2D(int h, int w, F _f, const T& i) : f(_f), I(i) { init(h, w); }
void init(int h, int w) {
H = W = 1;
while (H < h) H <<= 1;
while (W < w) W <<= 1;
seg.assign(4 * H * W, I);
}
// build にのみ呼ぶ
void set(int h, int w, const T& x) { seg[id(h + H, w + W)] = x; }
void build() {
// w in [W, 2W)
for (int w = W; w < 2 * W; w++) {
for (int h = H - 1; h; h--) {
seg[id(h, w)] = f(seg[id(2 * h + 0, w)], seg[id(2 * h + 1, w)]);
}
}
// h in [0, 2H)
for (int h = 0; h < 2 * H; h++) {
for (int w = W - 1; w; w--) {
seg[id(h, w)] = f(seg[id(h, 2 * w + 0)], seg[id(h, 2 * w + 1)]);
}
}
}
T get(int h, int w) const { return seg[id(h + H, w + W)]; }
T operator()(int h, int w) const { return seg[id(h + H, w + W)]; }
void update(int h, int w, const T& x) {
h += H, w += W;
seg[id(h, w)] = x;
for (int i = h >> 1; i; i >>= 1) {
seg[id(i, w)] = f(seg[id(2 * i + 0, w)], seg[id(2 * i + 1, w)]);
}
for (; h; h >>= 1) {
for (int j = w >> 1; j; j >>= 1) {
seg[id(h, j)] = f(seg[id(h, 2 * j + 0)], seg[id(h, 2 * j + 1)]);
}
}
}
T _inner_query(int h, int w1, int w2) {
T res = I;
for (; w1 < w2; w1 >>= 1, w2 >>= 1) {
if (w1 & 1) res = f(res, seg[id(h, w1)]), w1++;
if (w2 & 1) --w2, res = f(res, seg[id(h, w2)]);
}
return res;
}
// [ (h1,w1), (h2,w2) ) 半開
T query(int h1, int w1, int h2, int w2) {
if (h1 >= h2 || w1 >= w2) return I;
T res = I;
h1 += H, h2 += H, w1 += W, w2 += W;
for (; h1 < h2; h1 >>= 1, h2 >>= 1) {
if (h1 & 1) res = f(res, _inner_query(h1, w1, w2)), h1++;
if (h2 & 1) --h2, res = f(res, _inner_query(h2, w1, w2));
}
return res;
}
};
/**
* @brief 二次元セグメント木
* @docs docs/data-structure-2d/2d-segment-tree.md
*/