Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions docs/structure/rectangle-apply-point-get.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
title: Rectangle Apply Point Get
documentation_of: //structure/rectangle_apply_point_get.hpp
---

長方形領域に作用素を掛け、一点に掛かっている作用素を取得するデータ構造です。

座標範囲を先に指定し、その範囲内の長方形作用と一点取得をオンラインに処理できます。

作用素 `F` はモノイドとして扱います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

作用素側にTimeみたいな時刻情報をもたせれば可換にできる


```
F composition(F f, F g)
F id()
```

`composition(f, g)` は ACL の `lazy_segtree` と同じく、作用 `g` の後に作用 `f` を適用する合成、`id()` は単位元です。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

作用素側にTimeみたいな時刻情報をもたせれば可換にできる


## コンストラクタ

```
rectangle_apply_point_get<F, composition, id, T = int>(T xl, T xr, T yl, T yr)
```

座標範囲 $[xl, xr) \times [yl, yr)$ を指定する。
`T` は座標の型です。

## apply

```
void apply(T l, T r, T d, T u, F f)
```

領域 $[l, r) \times [d, u)$ に作用 `f` を掛ける。

### 計算量
座標範囲の幅を $X = xr - xl, Y = yr - yl$ として
- $O(\log X \log Y)$

新しく作られる内部ノード数も $O(\log X \log Y)$。

## get

```
F get(T x, T y)
```

点 `(x, y)` に掛かっている作用素の合成を返す。

### 計算量
座標範囲の幅を $X = xr - xl, Y = yr - yl$ として
- $O(\log X \log Y)$

内部ノードは作らない。
114 changes: 114 additions & 0 deletions structure/rectangle_apply_point_get.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#ifndef HARUILIB_STRUCTURE_RECTANGLE_APPLY_POINT_GET_HPP
#define HARUILIB_STRUCTURE_RECTANGLE_APPLY_POINT_GET_HPP

#include <cassert>
#include <vector>

template <class F, F (*composition)(F, F), F (*id)(), class T = int>
struct rectangle_apply_point_get {
Comment on lines +7 to +8

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

作用素側にTimeみたいな時刻情報をもたせれば可換にできる

rectangle_apply_point_get(T xl, T xr, T yl, T yr)
: xl(xl), xr(xr), yl(yl), yr(yr), root(-1) {
assert(xl < xr);
assert(yl < yr);
root = new_x_node();
}

void apply(T l, T r, T d, T u, F f) {
assert(xl <= l && l <= r && r <= xr);
assert(yl <= d && d <= u && u <= yr);
apply_x(root, xl, xr, l, r, d, u, f);
}

F get(T x, T y) const {
assert(xl <= x && x < xr);
assert(yl <= y && y < yr);
return get_x(root, xl, xr, x, y);
}

private:
struct XNode {
int left, right, y_root;
};

struct YNode {
int left, right;
F val;
};

int new_x_node() {
xs.push_back({-1, -1, -1});
return (int)xs.size() - 1;
}

int new_y_node() {
ys.push_back({-1, -1, id()});
return (int)ys.size() - 1;
}

void apply_x(int k, T nl, T nr, T ql, T qr, T qd, T qu, F f) {
if (qr <= nl || nr <= ql) return;
if (ql <= nl && nr <= qr) {
xs[k].y_root = apply_y(xs[k].y_root, yl, yr, qd, qu, f);
return;
}

T mid = nl + (nr - nl) / 2;
if (ql < mid) {
if (xs[k].left == -1) {
int child = new_x_node();
xs[k].left = child;
}
apply_x(xs[k].left, nl, mid, ql, qr, qd, qu, f);
}
if (mid < qr) {
if (xs[k].right == -1) {
int child = new_x_node();
xs[k].right = child;
}
apply_x(xs[k].right, mid, nr, ql, qr, qd, qu, f);
}
}

int apply_y(int k, T nl, T nr, T ql, T qr, F f) {
if (qr <= nl || nr <= ql) return k;
if (k == -1) k = new_y_node();
if (ql <= nl && nr <= qr) {
ys[k].val = composition(f, ys[k].val);
return k;
}

T mid = nl + (nr - nl) / 2;
if (ql < mid) ys[k].left = apply_y(ys[k].left, nl, mid, ql, qr, f);
if (mid < qr) ys[k].right = apply_y(ys[k].right, mid, nr, ql, qr, f);
return k;
}

F get_x(int k, T nl, T nr, T x, T y) const {
if (k == -1) return id();

F res = get_y(xs[k].y_root, yl, yr, y);
if (nr - nl == 1) return res;

T mid = nl + (nr - nl) / 2;
if (x < mid) return composition(get_x(xs[k].left, nl, mid, x, y), res);
return composition(get_x(xs[k].right, mid, nr, x, y), res);
}

F get_y(int k, T nl, T nr, T y) const {
if (k == -1) return id();

F res = ys[k].val;
if (nr - nl == 1) return res;

T mid = nl + (nr - nl) / 2;
if (y < mid) return composition(get_y(ys[k].left, nl, mid, y), res);
return composition(get_y(ys[k].right, mid, nr, y), res);
}

T xl, xr, yl, yr;
int root;
std::vector<XNode> xs;
std::vector<YNode> ys;
};

#endif // HARUILIB_STRUCTURE_RECTANGLE_APPLY_POINT_GET_HPP
84 changes: 84 additions & 0 deletions test/verify/structure/yosupo-rectangle-add-point-get.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#define PROBLEM "https://judge.yosupo.jp/problem/rectangle_add_point_get"
#include "template/template.hpp"
#include "structure/rectangle_apply_point_get.hpp"

#include <algorithm>
#include <vector>

ll composition(ll f, ll g) {
return f + g;
}

ll id() {
return 0;
}

struct Rect {
int l, d, r, u;
ll w;
};

struct Query {
int type;
Rect rect;
int x, y;
};

int main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);

int N, Q; cin >> N >> Q;
vector<Rect> rects(N);
for (int i=0; i<N; i++) {
cin >> rects[i].l >> rects[i].d >> rects[i].r >> rects[i].u >> rects[i].w;
}

vector<Query> qs(Q);
vector<int> xs, ys;
for (int q=0; q<Q; q++) {
cin >> qs[q].type;
if (qs[q].type == 0) {
cin >> qs[q].rect.l >> qs[q].rect.d >> qs[q].rect.r >> qs[q].rect.u >> qs[q].rect.w;
}
else {
cin >> qs[q].x >> qs[q].y;
xs.push_back(qs[q].x);
ys.push_back(qs[q].y);
}
}

if (xs.empty()) return 0;

sort(xs.begin(), xs.end());
xs.erase(unique(xs.begin(), xs.end()), xs.end());
sort(ys.begin(), ys.end());
ys.erase(unique(ys.begin(), ys.end()), ys.end());

auto get_x = [&](int x) {
return lower_bound(xs.begin(), xs.end(), x) - xs.begin();
};
auto get_y = [&](int y) {
return lower_bound(ys.begin(), ys.end(), y) - ys.begin();
};
auto apply = [&](rectangle_apply_point_get<ll, composition, id>& g, const Rect& rect) {
int l = get_x(rect.l);
int r = get_x(rect.r);
int d = get_y(rect.d);
int u = get_y(rect.u);
g.apply(l, r, d, u, rect.w);
};

rectangle_apply_point_get<ll, composition, id> g(0, (int)xs.size(), 0, (int)ys.size());
for (auto& rect : rects) apply(g, rect);

for (auto& q : qs) {
if (q.type == 0) {
apply(g, q.rect);
}
else {
cout << g.get(get_x(q.x), get_y(q.y)) << "\n";
}
}

return 0;
}
Loading