Skip to content

Commit ba050c6

Browse files
committed
update
1 parent 4d19fa8 commit ba050c6

18 files changed

Lines changed: 540 additions & 7 deletions
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#pragma once
2+
3+
template <class T, int B = 8>
4+
struct PersistentArray {
5+
struct Node {
6+
T val;
7+
Node* child[B] = {};
8+
Node() {}
9+
Node(const T& v) : val(v) {}
10+
};
11+
Node* root;
12+
vector<Node*> snapshots;
13+
PersistentArray() : root(nullptr) {}
14+
T get(Node* t, int k) { return k == 0 ? t->val : get(t->child[k % B], k / B); }
15+
T get(const int& k) { return get(root, k); }
16+
pair<Node*, T*> mutable_get(Node* t, int k) {
17+
t = t ? new Node(*t) : new Node();
18+
if (k == 0) return {t, &t->val};
19+
auto p = mutable_get(t->child[k % B], k / B);
20+
t->child[k % B] = p.first;
21+
return {t, p.second};
22+
}
23+
T* mutable_get(const int& k) {
24+
auto ret = mutable_get(root, k);
25+
root = ret.first;
26+
return ret.second;
27+
}
28+
Node* build(Node* t, const T& val, int k) {
29+
if (!t) t = new Node();
30+
if (k == 0) {
31+
t->val = val;
32+
return t;
33+
}
34+
t->child[k % B] = build(t->child[k % B], val, k / B);
35+
return t;
36+
}
37+
void build(const vector<T>& v) {
38+
root = nullptr;
39+
for (int i = 0; i < v.size(); i++) root = build(root, v[i], i);
40+
}
41+
int take_snapshot() {
42+
snapshots.push_back(root);
43+
return snapshots.size() - 1;
44+
}
45+
void apply_snapshot(int k) {
46+
root = snapshots[k];
47+
}
48+
};
49+
50+
/**
51+
* @brief Persistent Array
52+
* @docs docs/val-structure/persistent-array.md
53+
*/

‎data-structure/slope-trick.hpp‎

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#pragma once
2+
3+
template <class T>
4+
struct SlopeTrick {
5+
const T INF = numeric_limits<T>::max() / 3;
6+
T min_f;
7+
priority_queue<T, vector<T>, less<> > pq_l;
8+
priority_queue<T, vector<T>, greater<> > pq_r;
9+
T add_l, add_r;
10+
SlopeTrick() : min_f(0), add_l(0), add_r(0) {}
11+
T get_min() const { return min_f; }
12+
pair<T, T> get_min_range() const { return {top_l(), top_r()}; }
13+
// f(x) += a
14+
void add_const(const T& a) { min_f += a; }
15+
// f(x) += max(0, x - a)
16+
void add_x_minus_a(const T& a) {
17+
min_f += max(T(0), top_l() - a);
18+
push_l(a);
19+
push_r(pop_l());
20+
}
21+
// f(x) += max(a - x, 0)
22+
void add_a_minus_x(const T& a) {
23+
min_f += max(T(0), a - top_r());
24+
push_r(a);
25+
push_l(pop_r());
26+
}
27+
// f(x) += abs(x - a)
28+
void add_abs(const T& a) {
29+
add_a_minus_x(a);
30+
add_x_minus_a(a);
31+
}
32+
// f(x) <- min_{y <= x} f(y)
33+
// \/ -> \_
34+
void clear_right() {
35+
while (!pq_r.empty()) pq_r.pop();
36+
}
37+
// f(x) <- min_{x <= y} f(y)
38+
// \/ -> _/
39+
void clear_left() {
40+
while (!pq_l.empty()) pq_l.pop();
41+
}
42+
// f(x) <- min_{x-b <= y <= x-a} f(y)
43+
// \/ -> \_/
44+
void shift(const T& a, const T& b) {
45+
assert(a <= b);
46+
add_l += a;
47+
add_r += b;
48+
}
49+
50+
T get_destructive(const T& x) {
51+
T ret = min_f;
52+
while (!pq_l.empty()) ret += max(T(0), pop_l() - x);
53+
while (!pq_r.empty()) ret += max(T(0), x - pop_r());
54+
return ret;
55+
}
56+
void merge(SlopeTrick& st) {
57+
if (st.size() > size()) {
58+
swap(st.pq_l, pq_l);
59+
swap(st.pq_r, pq_r);
60+
swap(st.add_l, add_l);
61+
swap(st.add_r, add_r);
62+
swap(st.min_f, min_f);
63+
}
64+
while (!st.pq_r.empty()) add_x_minus_a(st.pop_r());
65+
while (!st.pq_l.empty()) add_a_minus_x(st.pop_l());
66+
min_f += st.min_f;
67+
}
68+
69+
private:
70+
void push_r(const T& a) { pq_r.push(a - add_r); }
71+
T top_r() const { return pq_r.empty() ? INF : pq_r.top() + add_r; }
72+
T pop_r() {
73+
T val = top_r();
74+
if (!pq_r.empty()) pq_r.pop();
75+
return val;
76+
}
77+
void push_l(const T& a) { pq_l.push(a - add_l); }
78+
T top_l() const { return pq_l.empty() ? -INF : pq_l.top() + add_l; }
79+
T pop_l() {
80+
T val = top_l();
81+
if (!pq_l.empty()) pq_l.pop();
82+
return val;
83+
}
84+
size_t size() { return pq_l.size() + pq_r.size(); }
85+
};
86+
87+
/**
88+
* @brief Slope Trick
89+
* @docs docs/data-structure/slope-trick.md
90+
*/

‎docs/data-structure/slope-trick.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
区分線形凸関数を管理するデータ構造.
3+
4+
最小値と,傾きが変わる点を 2 つの priority queue で管理する.
5+
DP の遷移で $\max(0,x-a)$, $\max(0,a-x)$, $|x-a|$ を足したり,片側の累積 min を取ったりするときに使う.
6+
7+
- `get_min()`:現在の関数の最小値を返す.
8+
- `get_min_range()`:最小値を取る区間を返す.
9+
- `add_const(a)`:関数全体に定数 $a$ を足す.
10+
- `add_x_minus_a(a)`:$\max(0,x-a)$ を足す.
11+
- `add_a_minus_x(a)`:$\max(0,a-x)$ を足す.
12+
- `add_abs(a)`:$|x-a|$ を足す.
13+
- `clear_right()`:$f(x)\gets\min_{y\leq x} f(y)$ とする.
14+
- `clear_left()`:$f(x)\gets\min_{x\leq y} f(y)$ とする.
15+
- `shift(a, b)`:$f(x)\gets\min_{x-b\leq y\leq x-a} f(y)$ とする.
16+
17+
https://ei1333.github.io/library/structure/others/slope-trick.hpp.html
18+
https://maspypy.com/slope-trick-1-%E8%A7%A3%E8%AA%AC%E7%B7%A8
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# 永続セグメント木
2+
3+
https://info.atcoder.jp/entry/algorithm_lectures/persistent_segment_tree
4+
5+
完全永続的(fully persistent)なセグメント木
6+
7+
https://nyaannyaan.github.io/library/segment-tree/persistent-segment-tree.hpp.html
8+
9+
`set`, `apply`, `get`, `prod` それぞれ以下のように 3 パターンの方法で呼び出せる
10+
11+
- `set(p, v)` : 最新の木で位置 `p` の値を `v` に更新した新たな木の根へのポインタを返す
12+
- `set(time, p, v)` : 時刻 `time` の木で位置 `p` の値を `v` に更新した新たな木の根へのポインタを返す
13+
- `set(ptr, p, v)` : 根が `ptr` の木で位置 `p` の値を `v` に更新した新たな木の根へのポインタを返す

‎docs/tree/tree-jump.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
根付き木上で ancestor, LCA, パス上の jump を処理するデータ構造.
2+
3+
木を与えて `build()` すると,doubling により祖先を管理する.
4+
コンストラクタに隣接リストを渡した場合は自動で `build()` される.
5+
6+
- `add_edge(u, v)`:無向辺 $uv$ を追加する.
7+
- `build()`:頂点 $0$ を根として前処理する.
8+
- `ancestor(x, k)`:頂点 $x$ から $k$ 個親方向へ進んだ頂点を返す.存在しない場合は `-1` を返す.
9+
- `lca(x, y)`:頂点 $x,y$ の LCA を返す.
10+
- `dist(x, y)`:頂点 $x,y$ 間の距離を返す.
11+
- `jump(x, y, k)`:$x$ から $y$ への単純パス上で,$x$ から $k$ 辺進んだ頂点を返す.存在しない場合は `-1` を返す.
12+
13+
前処理は $O(N\log N)$ 時間,クエリは $O(\log N)$ 時間.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
永続配列.
2+
3+
長さ $N$ の列 $A=(A_0,A_1,\dots,A_{N-1})$ を管理し,更新前の状態を保存して後から戻せるようにする.
4+
5+
- `build(v)`:列 `v` で初期化する.
6+
- `get(k)`:$A_k$ を取得する.
7+
- `mutable_get(k)`:$A_k$ へのポインタを取得する.必要な頂点だけコピーされるため,値を代入すると新しい状態が作られる.
8+
- `take_snapshot()`:現在の状態を保存し,その番号を返す.
9+
- `apply_snapshot(k)`:`take_snapshot` で保存した状態 `k` に戻す.
10+
11+
内部では添字を $B$ 進数で見た trie を永続化している.
12+
各操作でコピーされる頂点数は $O(\log_B N)$ 個.

‎graph/graph.hpp‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#pragma once
2+
3+
struct Graph {
4+
int n;
5+
vector<vector<int>> g;
6+
Graph() : Graph(0) {}
7+
Graph(int size) : n(size), g(size) {}
8+
void add_edge(int x, int y) {
9+
g[x].push_back(y);
10+
g[y].push_back(x);
11+
}
12+
void add_edge_directed(int from, int to) {
13+
g[from].push_back(to);
14+
}
15+
};

‎math/root-extension.hpp‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#pragma once
2+
3+
// T[x]/(x^s-r)
4+
template <class T, int s, auto r>
5+
struct RootExtension {
6+
using F = RootExtension;
7+
array<T, s> a;
8+
RootExtension() { a.fill(T{}); }
9+
RootExtension(const T& x) {
10+
a.fill(T{});
11+
a[0] = x;
12+
}
13+
T& operator[](int k) { return a[k]; }
14+
F& operator+=(const F& o) {
15+
for (int i = 0; i < s; i++) a[i] += o.a[i];
16+
return *this;
17+
}
18+
F& operator-=(const F& o) {
19+
for (int i = 0; i < s; i++) a[i] -= o.a[i];
20+
return *this;
21+
}
22+
F& operator*=(const F& o) {
23+
const T _r = T{r};
24+
array<T, s> b{};
25+
for (int i = 0; i < s; i++) {
26+
for (int j = 0; j < s - i; j++) b[i + j] += a[i] * o.a[j];
27+
for (int j = s - i; j < s; j++) b[i + j - s] += _r * a[i] * o.a[j];
28+
}
29+
swap(a, b);
30+
return *this;
31+
}
32+
F operator+(const F& o) const { return F(*this) += o; }
33+
F operator-(const F& o) const { return F(*this) -= o; }
34+
F operator*(const F& o) const { return F(*this) *= o; }
35+
F operator-() const {
36+
F ret(*this);
37+
for (auto& v : ret.a) v = -v;
38+
return ret;
39+
}
40+
F pow(long long n) const {
41+
F ret = T{1}, x = *this;
42+
while (n) {
43+
if (n & 1) ret *= x;
44+
x *= x;
45+
n >>= 1;
46+
}
47+
return ret;
48+
}
49+
T test() const { return T{r}; }
50+
};

‎math/util.hpp‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,24 @@ long long isqrt(long long n) {
2727
while (x * x > n) x--;
2828
return x;
2929
}
30+
long long floor_root(long long n, int k) {
31+
assert(n >= 0);
32+
if (n == 0) return 0;
33+
assert(k >= 1);
34+
if (k == 1) return n;
35+
if (k > 64) return 1;
36+
long long x = round(pow((long double)n, 1.0L / k));
37+
auto check = [&](long long a) {
38+
if (a <= 0) return true;
39+
__int128_t p = 1;
40+
for (int i = 0; i < k; ++i)
41+
if ((p *= a) > n) return false;
42+
return true;
43+
};
44+
while (check(x + 1)) x++;
45+
while (!check(x)) x--;
46+
return x;
47+
}
3048
// return g=gcd(a,b)
3149
// a*x+b*y=g
3250
// - b!=0 -> 0<=x<|b|/g

‎matrix/matrix.hpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ struct Matrix {
3030
Matrix operator-(const Matrix& r) { return Matrix(*this) -= r; }
3131
Matrix operator*(const Matrix& r) {
3232
assert(w == r.h);
33-
cerr.flush();
3433
Matrix ret(h, r.w);
3534
for (int i = 0; i < h; i++)
3635
for (int j = 0; j < r.w; j++)
3736
for (int k = 0; k < w; k++)
3837
ret.add(i, j, get(i, k) * r.get(k, j));
3938
return ret;
4039
}
40+
Matrix& operator*=(const Matrix& r) { return *this = *this * r; }
4141
Matrix pow(long long n) const {
4242
Matrix ret = id(h);
4343
Matrix mat(*this);
@@ -118,4 +118,4 @@ struct Matrix {
118118
}
119119
return os;
120120
}
121-
};
121+
};

0 commit comments

Comments
 (0)