This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub kmyk/competitive-programming-library
/** * @note O(h * w) space */ template <class CommutativeMonoid> struct segment_tree_2d { typedef typename CommutativeMonoid::value_type value_type; int h1, w1; int h, w; vector<value_type> data; CommutativeMonoid mon; segment_tree_2d() = default; segment_tree_2d(int h_, int w_, value_type initial_value = CommutativeMonoid().unit(), CommutativeMonoid const & mon_ = CommutativeMonoid()) : h1(h_), w1(w_), mon(mon_) { h = pow(2, ceil(log2(h_))); w = pow(2, ceil(log2(w_))); data.resize((2 * h - 1) * (2 * w - 1), mon.unit()); REP_R (y, h) REP_R (x, w) { if (y < h - 1) { at(y, x) = mon.append( at(2 * y + 1, x), at(2 * y + 2, x)); } else if (x < w - 1) { at(y, x) = mon.append( at(y, 2 * x + 1), at(y, 2 * x + 2)); } else if (y < h - 1 + h_ and x < w - 1 + w_) { at(y, x) = initial_value; } } } inline value_type & at(int y, int x) { return data[y * (2 * w - 1) + x]; } inline value_type const & at(int y, int x) const { return data[y * (2 * w - 1) + x]; } /** * @note O(log h * log w) */ void point_set(int y, int x, value_type value) { assert (0 <= y and y < h1 and 0 <= x and x < w1); for (int i = y + h; i > 0; i /= 2) { // 1-based for (int j = x + w; j > 0; j /= 2) { // 1-based if (i >= h and j >= w) { at(i - 1, j - 1) = value; } else if (j >= w) { at(i - 1, j - 1) = mon.append( at(2 * i - 1, j - 1), at(2 * i, j - 1)); } else { at(i - 1, j - 1) = mon.append( at(i - 1, 2 * j - 1), at(i - 1, 2 * j)); } } } } /** * @note O(log h * log w) */ value_type area_concat(int ly, int lx, int ry, int rx) const { assert (0 <= ly and ly <= ry and ry <= h1); assert (0 <= lx and lx <= rx and rx <= w1); return area_concat(0, 0, 0, 0, h, w, false, ly, lx, ry, rx); } value_type area_concat(int i, int j, int ily, int jlx, int iry, int jrx, bool p, int ly, int lx, int ry, int rx) const { if (iry <= ly or ry <= ily or jrx <= lx or rx <= jlx) { return mon.unit(); } else if (ly <= ily and iry <= ry and lx <= jlx and jrx <= rx) { return at(i, j); } else if ((ly <= ily and iry <= ry) or (p and not (lx <= jlx and jrx <= rx))) { return mon.append( area_concat(i, 2 * j + 1, ily, jlx, iry, (jlx + jrx) / 2, not p, ly, lx, ry, rx), area_concat(i, 2 * j + 2, ily, (jlx + jrx) / 2, iry, jrx, not p, ly, lx, ry, rx)); } else { return mon.append( area_concat(2 * i + 1, j, ily, jlx, (ily + iry) / 2, jrx, not p, ly, lx, ry, rx), area_concat(2 * i + 2, j, (ily + iry) / 2, jlx, iry, jrx, not p, ly, lx, ry, rx)); } } /** * @note call area_concat O((ry - ly) / h * (rx - lx) / w) times */ value_type area_concat_torus(int ly, int lx, int ry, int rx) const { value_type acc = mon.unit(); while (ly < 0) { ly += h1; ry += h1; } while (lx < 0) { lx += w1; rx += w1; } for (int bi = ly / h1; bi <= (ry - 1) / h1; ++ bi) { int ly1 = (bi == ly / h1 ? ly % h1 : 0); int ry1 = (bi == ry / h1 ? ry % h1 : h1); for (int bj = lx / w1; bj <= (rx - 1) / w1; ++ bj) { int lx1 = (bj == lx / w1 ? lx % w1 : 0); int rx1 = (bj == rx / w1 ? rx % w1 : w1); acc = mon.append(acc, area_concat(ly1, lx1, ry1, rx1)); } } return acc; } }; struct max_monoid { typedef int value_type; int unit() const { return INT_MIN; } int append(int a, int b) const { return max(a, b); } }; struct plus_monoid { typedef int value_type; int unit() const { return 0; } int append(int a, int b) const { return a + b; } }; unittest { default_random_engine gen; REP (iteration, 100) { int h = uniform_int_distribution<int>(1, 30)(gen); int w = uniform_int_distribution<int>(1, 30)(gen); vector<vector<int> > a(h, vector<int>(w)); segment_tree_2d<plus_monoid> segtree(h, w); REP (y, h) REP (x, w) { a[y][x] = uniform_int_distribution<int>(-10, 10)(gen); segtree.point_set(y, x, a[y][x]); } REP (y, h) REP (x, w) { assert (a[y][x] == segtree.area_concat(y, x, y + 1, x + 1)); } REP (iteration, 100) { int ly = uniform_int_distribution<int>(0, h - 1)(gen); int lx = uniform_int_distribution<int>(0, w - 1)(gen); int ry = uniform_int_distribution<int>(ly + 1, h)(gen); int rx = uniform_int_distribution<int>(lx + 1, w)(gen); int acc = 0; REP3 (y, ly, ry) { REP3 (x, lx, rx) { acc += a[y][x]; } } assert (acc == segtree.area_concat(ly, lx, ry, rx)); } REP (iteration, 10) { int ly = uniform_int_distribution<int>(- 100, 50)(gen); int lx = uniform_int_distribution<int>(- 100, 50)(gen); int ry = uniform_int_distribution<int>(ly, 100)(gen); int rx = uniform_int_distribution<int>(lx, 100)(gen); int acc = 0; REP3 (y, ly, ry) { REP3 (x, lx, rx) { acc += a[(y % h + h) % h][(x % w + w) % w]; } } assert (acc == segtree.area_concat_torus(ly, lx, ry, rx)); } } }
#line 1 "old/segment-tree-2d.inc.cpp" /** * @note O(h * w) space */ template <class CommutativeMonoid> struct segment_tree_2d { typedef typename CommutativeMonoid::value_type value_type; int h1, w1; int h, w; vector<value_type> data; CommutativeMonoid mon; segment_tree_2d() = default; segment_tree_2d(int h_, int w_, value_type initial_value = CommutativeMonoid().unit(), CommutativeMonoid const & mon_ = CommutativeMonoid()) : h1(h_), w1(w_), mon(mon_) { h = pow(2, ceil(log2(h_))); w = pow(2, ceil(log2(w_))); data.resize((2 * h - 1) * (2 * w - 1), mon.unit()); REP_R (y, h) REP_R (x, w) { if (y < h - 1) { at(y, x) = mon.append( at(2 * y + 1, x), at(2 * y + 2, x)); } else if (x < w - 1) { at(y, x) = mon.append( at(y, 2 * x + 1), at(y, 2 * x + 2)); } else if (y < h - 1 + h_ and x < w - 1 + w_) { at(y, x) = initial_value; } } } inline value_type & at(int y, int x) { return data[y * (2 * w - 1) + x]; } inline value_type const & at(int y, int x) const { return data[y * (2 * w - 1) + x]; } /** * @note O(log h * log w) */ void point_set(int y, int x, value_type value) { assert (0 <= y and y < h1 and 0 <= x and x < w1); for (int i = y + h; i > 0; i /= 2) { // 1-based for (int j = x + w; j > 0; j /= 2) { // 1-based if (i >= h and j >= w) { at(i - 1, j - 1) = value; } else if (j >= w) { at(i - 1, j - 1) = mon.append( at(2 * i - 1, j - 1), at(2 * i, j - 1)); } else { at(i - 1, j - 1) = mon.append( at(i - 1, 2 * j - 1), at(i - 1, 2 * j)); } } } } /** * @note O(log h * log w) */ value_type area_concat(int ly, int lx, int ry, int rx) const { assert (0 <= ly and ly <= ry and ry <= h1); assert (0 <= lx and lx <= rx and rx <= w1); return area_concat(0, 0, 0, 0, h, w, false, ly, lx, ry, rx); } value_type area_concat(int i, int j, int ily, int jlx, int iry, int jrx, bool p, int ly, int lx, int ry, int rx) const { if (iry <= ly or ry <= ily or jrx <= lx or rx <= jlx) { return mon.unit(); } else if (ly <= ily and iry <= ry and lx <= jlx and jrx <= rx) { return at(i, j); } else if ((ly <= ily and iry <= ry) or (p and not (lx <= jlx and jrx <= rx))) { return mon.append( area_concat(i, 2 * j + 1, ily, jlx, iry, (jlx + jrx) / 2, not p, ly, lx, ry, rx), area_concat(i, 2 * j + 2, ily, (jlx + jrx) / 2, iry, jrx, not p, ly, lx, ry, rx)); } else { return mon.append( area_concat(2 * i + 1, j, ily, jlx, (ily + iry) / 2, jrx, not p, ly, lx, ry, rx), area_concat(2 * i + 2, j, (ily + iry) / 2, jlx, iry, jrx, not p, ly, lx, ry, rx)); } } /** * @note call area_concat O((ry - ly) / h * (rx - lx) / w) times */ value_type area_concat_torus(int ly, int lx, int ry, int rx) const { value_type acc = mon.unit(); while (ly < 0) { ly += h1; ry += h1; } while (lx < 0) { lx += w1; rx += w1; } for (int bi = ly / h1; bi <= (ry - 1) / h1; ++ bi) { int ly1 = (bi == ly / h1 ? ly % h1 : 0); int ry1 = (bi == ry / h1 ? ry % h1 : h1); for (int bj = lx / w1; bj <= (rx - 1) / w1; ++ bj) { int lx1 = (bj == lx / w1 ? lx % w1 : 0); int rx1 = (bj == rx / w1 ? rx % w1 : w1); acc = mon.append(acc, area_concat(ly1, lx1, ry1, rx1)); } } return acc; } }; struct max_monoid { typedef int value_type; int unit() const { return INT_MIN; } int append(int a, int b) const { return max(a, b); } }; struct plus_monoid { typedef int value_type; int unit() const { return 0; } int append(int a, int b) const { return a + b; } }; unittest { default_random_engine gen; REP (iteration, 100) { int h = uniform_int_distribution<int>(1, 30)(gen); int w = uniform_int_distribution<int>(1, 30)(gen); vector<vector<int> > a(h, vector<int>(w)); segment_tree_2d<plus_monoid> segtree(h, w); REP (y, h) REP (x, w) { a[y][x] = uniform_int_distribution<int>(-10, 10)(gen); segtree.point_set(y, x, a[y][x]); } REP (y, h) REP (x, w) { assert (a[y][x] == segtree.area_concat(y, x, y + 1, x + 1)); } REP (iteration, 100) { int ly = uniform_int_distribution<int>(0, h - 1)(gen); int lx = uniform_int_distribution<int>(0, w - 1)(gen); int ry = uniform_int_distribution<int>(ly + 1, h)(gen); int rx = uniform_int_distribution<int>(lx + 1, w)(gen); int acc = 0; REP3 (y, ly, ry) { REP3 (x, lx, rx) { acc += a[y][x]; } } assert (acc == segtree.area_concat(ly, lx, ry, rx)); } REP (iteration, 10) { int ly = uniform_int_distribution<int>(- 100, 50)(gen); int lx = uniform_int_distribution<int>(- 100, 50)(gen); int ry = uniform_int_distribution<int>(ly, 100)(gen); int rx = uniform_int_distribution<int>(lx, 100)(gen); int acc = 0; REP3 (y, ly, ry) { REP3 (x, lx, rx) { acc += a[(y % h + h) % h][(x % w + w) % w]; } } assert (acc == segtree.area_concat_torus(ly, lx, ry, rx)); } } }