Skip to content

Commit 440abb0

Browse files
committed
update
1 parent f821b37 commit 440abb0

File tree

10 files changed

+362
-190
lines changed

10 files changed

+362
-190
lines changed

data-structure/range-array.hpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
// 区間に値を対応づける
44
// range set point get + enumerate
5-
template <class T>
5+
template <class T, bool merge = true>
66
struct RangeArray {
77
private:
88
int n;
@@ -30,12 +30,23 @@ struct RangeArray {
3030
if (r <= l1) break;
3131
it++;
3232
int r1 = *it;
33-
ret.push_back({l1, r1});
33+
ret.push_back({max(l, l1), min(r, r1)});
3434
}
3535
return ret;
3636
}
37-
void set(int l, int r, T v) {
38-
for (auto it = s.lower_bound(l); it != s.end();) {
37+
void update(int l, int r, T v) {
38+
assert(0 <= l && l < r && r <= n);
39+
auto it = s.lower_bound(l);
40+
if (merge && it != s.begin()) {
41+
it--;
42+
int x = *it;
43+
it++;
44+
if (data[x] == v) {
45+
l = x;
46+
it--;
47+
}
48+
}
49+
while (it != s.end()) {
3950
int l1 = *it;
4051
if (r <= l1) break;
4152
it++;
@@ -48,6 +59,11 @@ struct RangeArray {
4859
break;
4960
}
5061
}
62+
if (merge && it != s.end()) {
63+
int x = *it;
64+
if (x < n && data[x] == v)
65+
it = s.erase(it);
66+
}
5167
s.insert(l);
5268
data[l] = v;
5369
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
形式的 Dirichlet 級数ライブラリ.
2+
3+
prefix の具体的な値を管理する.
4+
5+
## 形式的 Dirichlet 級数
6+
7+
$R$ を環とする.
8+
9+
$R$ の数列 $A,B:\mathbb{N}\to R$ の Dirichlet 積 $A*B:\mathbb{N}\to R$ を以下で定める.
10+
$$(A*B)(k)=\sum_{ij=k}A(i)B(j)$$
11+
12+
$R^{\mathbb{N}}$ に対して加算を成分毎の加算,乗算を Dirichlet 積とすると環になる.これを形式的 Dirichlet 級数環と呼ぶことにする.
13+
以下特に断りのない場合積の記号 $*$ は省略する.
14+
15+
Dirichlet 級数の記法を流用し $A\in R^{\mathbb{N}}$ を以下のようにも表す:
16+
$$\sum_{n=1}^{\infty}\frac{A(n)}{n^{-s}}.$$
17+
また $[n^{-s}]A=A(n)$ とする.
18+
19+
この記法を用いれば加法の単位元は $0$,乗法の単位元は $1$ である.
20+
また Dirichlet 級数 $A$ の逆元が存在する必要十分条件は $[1^{-s}]A$ が逆元を持つことである.
21+
22+
## 乗算/除算
23+
24+
$A,B$ の前 $N$ 項がわかっているとき,$AB$ の前 $N$ 項が $O(N\log N)$ 時間で計算できる.
25+
26+
## exp/log
27+
28+
- [https://atcoder.jp/contests/abc428/editorial/14241]
29+
30+
形式的 Dirichlet 級数 $A$ について $[1^{-s}]A$ が適当な条件を満たすとき形式的冪級数 $\exp x,\log x$ との合成によって $\exp A,\log A$ を考えることができる.
31+
32+
$A$ から $\exp A$ や $\log A$ を高速に計算できないだろうか.
33+
34+
ここで $n$ の重複を込めた素因数の個数を $\Omega(n)$ として,演算子 $\mathfrak{D}$ を
35+
$$\mathfrak{D}\left(\sum_{n\geq 1}\frac{a_n}{n^s}\right)=\sum_{n\geq 1}\frac{a_n\Omega(n)}{n^s}$$
36+
37+
によって定める.これは微分に対応する演算になっており,以下の性質を満たす.
38+
- $\mathfrak{D}(A+B)=(\mathfrak{D} A)+(\mathfrak{D} B)$.
39+
- $\mathfrak{D}(AB)=(\mathfrak{D} A)B+A(\mathfrak{D} B)$.
40+
- $\mathfrak{D}(A^k)=k(\mathfrak{D} A)A^{k-1}$.
41+
- 形式的冪級数 $f$ に対し,合成 $f(A)$ が定義されるならば $\mathfrak{D}(f(A))=f'(A)(\mathfrak{D} A)$.
42+
43+
> 逆に上二つの性質を満たす演算子は $\mathfrak{D}(p^{-s})$ を定めれば決まる.
44+
> $\mathfrak{D}(p^{-s})=p^{-s}$ とすれば上記の $\mathfrak{D}$ が得られる.
45+
46+
従って以下が成り立つ.
47+
$$\mathfrak{D}\exp A=(\mathfrak{D} A)\exp A,\quad \mathfrak{D}\log A=\frac{\mathfrak{D} A}{A}$$
48+
49+
これを用いれば $A$ の前 $N$ 項がわかっているとき $\exp,\log$ の前 $N$ 項は $O(N\log N)$ 時間で計算できる.

docs/segment-tree/lazy-segment-tree-util.md

Whitespace-only changes.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- `SegmentTreeSum` : 和
2+
- `SegmentTreeProd` : 積
3+
- `SegmentTreeMax` : max
4+
- `SegmentTreeMin` : min
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#pragma once
2+
3+
template <class mint>
4+
struct FormalDirichletSeries : vector<mint> {
5+
using vector<mint>::vector;
6+
using FDS = FormalDirichletSeries;
7+
FDS& operator+=(const mint& v) {
8+
if (1 < this->size()) (*this)[1] += v;
9+
return *this;
10+
}
11+
FDS& operator+=(const FDS& r) {
12+
if (r.size() > this->size()) this->resize(r.size());
13+
for (int i = 1; i < (int)r.size(); i++) (*this)[i] += r[i];
14+
return *this;
15+
}
16+
FDS& operator-=(const mint& v) {
17+
if (1 < this->size()) (*this)[1] -= v;
18+
return *this;
19+
}
20+
FDS& operator-=(const FDS& r) {
21+
if (r.size() > this->size()) this->resize(r.size());
22+
for (int i = 1; i < (int)r.size(); i++) (*this)[i] -= r[i];
23+
return *this;
24+
}
25+
FDS& operator*=(const mint& v) {
26+
for (int i = 1; i < (int)this->size(); i++) (*this)[i] *= v;
27+
return *this;
28+
}
29+
FDS& operator*=(const FDS& r) {
30+
FDS p(this->size(), 0);
31+
for (int i = 1; i < (int)r.size(); i++)
32+
for (int j = 1; i * j < (int)p.size(); j++)
33+
p[i * j] += r[i] * (*this)[j];
34+
return *this = p;
35+
}
36+
FDS& operator/=(const FDS& r) {
37+
mint c = r[1].inv();
38+
for (int i = 1; i < (int)this->size(); i++) {
39+
(*this)[i] *= c;
40+
for (int j = 2; j < (int)r.size() && i * j < (int)this->size(); j++)
41+
(*this)[i * j] -= (*this)[i] * r[j];
42+
}
43+
return *this;
44+
}
45+
FDS operator+(const mint& v) const { return FDS(*this) += v; }
46+
FDS operator+(const FDS& r) const { return FDS(*this) += r; }
47+
FDS operator-(const mint& v) const { return FDS(*this) -= v; }
48+
FDS operator-(const FDS& r) const { return FDS(*this) -= r; }
49+
FDS operator*(const mint& v) const { return FDS(*this) *= v; }
50+
FDS operator*(const FDS& r) const { return FDS(*this) *= r; }
51+
FDS operator/(const FDS& r) const { return FDS(*this) /= r; }
52+
FDS operator-() const {
53+
FDS ret(this->size());
54+
for (int i = 1; i < (int)this->size(); i++) ret[i] = -(*this)[i];
55+
return ret;
56+
}
57+
58+
static vector<mint> inv;
59+
static void init_inv() {
60+
if (inv.empty()) {
61+
inv.assign(33, 0);
62+
inv[1] = mint(1);
63+
auto mod = mint::get_mod();
64+
for (int i = 2; i < (int)inv.size(); i++) inv[i] = (-inv[mod % i]) * (mod / i);
65+
}
66+
}
67+
FDS integral() const {
68+
int n = this->size();
69+
if (n <= 1) return FDS(n);
70+
calc_lpf(n);
71+
FDS ret(n);
72+
init_inv();
73+
for (int i = 2; i < ret.size(); i++) ret[i] = (*this)[i] * inv[npf[i]];
74+
return ret;
75+
}
76+
FDS diff() const {
77+
calc_lpf(this->size());
78+
FDS ret(this->size());
79+
for (int i = 1; i < (int)this->size(); i++) ret[i] = (*this)[i] * npf[i];
80+
return ret;
81+
}
82+
FDS log(int n = -1) const {
83+
if (n == -1) n = (int)this->size();
84+
if (n <= 1) return FDS(n);
85+
assert((*this)[1] == mint(1));
86+
FDS f = *this;
87+
f.resize(n);
88+
return (f.diff() / f).integral();
89+
}
90+
FDS exp(int n = -1) const {
91+
if (n == -1) n = (int)this->size();
92+
if (n <= 1) return FDS(n);
93+
assert((*this)[1] == mint(0));
94+
auto df = this->diff();
95+
FDS ret(n);
96+
if (1 < n) ret[1] = 1;
97+
init_inv();
98+
for (int i = 1; i < n; i++) {
99+
if (i > 1) ret[i] *= inv[npf[i]];
100+
for (int j = 2; j < df.size() && i * j < n; j++) ret[i * j] += df[j] * ret[i];
101+
}
102+
return ret;
103+
}
104+
105+
static vector<int> npf;
106+
static vector<int> lpf;
107+
static void calc_lpf(int n) {
108+
if (lpf.empty()) {
109+
lpf = {0, 1, 2, 3, 2, 5, 2, 7};
110+
npf = {0, 0, 1, 1, 2, 1, 2, 1};
111+
}
112+
int l = lpf.size(), r = l;
113+
while (r <= n) r <<= 1;
114+
if (l == r) return;
115+
lpf.resize(r);
116+
npf.resize(r);
117+
for (int i = 2; i < l; i++) {
118+
if (lpf[i] != i) continue;
119+
for (int j = i * 2; j < r; j += i)
120+
if (lpf[j] == 0) lpf[j] = i;
121+
}
122+
for (int i = l; i < r; i++) {
123+
if (lpf[i] != 0) continue;
124+
lpf[i] = i;
125+
for (int j = i * 2; j < r; j += i)
126+
if (lpf[j] == 0) lpf[j] = i;
127+
}
128+
for (int i = l; i < r; i++)
129+
npf[i] = npf[i / lpf[i]] + 1;
130+
}
131+
};
132+
template <typename mint>
133+
vector<mint> FormalDirichletSeries<mint>::inv = {};
134+
template <typename mint>
135+
vector<int> FormalDirichletSeries<mint>::npf = {};
136+
template <typename mint>
137+
vector<int> FormalDirichletSeries<mint>::lpf = {};
138+
/**
139+
* @brief 形式的 Dirichlet 級数
140+
* @docs docs/number-theory/formal-dirichlet-series.md
141+
*/
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#pragma once
2+
#include "segment-tree/lazy-segment-tree.hpp"
3+
4+
namespace LazySegmentTreeUtil {
5+
template <class T>
6+
T Zero() { return T{}; }
7+
template <class T>
8+
T One() { return T{1}; }
9+
template <class T, T e>
10+
T Const() { return e; }
11+
template <class T>
12+
T Add(T x, T y) { return x + y; }
13+
template <class T>
14+
T Mul(T x, T y) { return x * y; }
15+
template <class T>
16+
T Max(T x, T y) { return x > y ? x : y; }
17+
template <class T>
18+
T Min(T x, T y) { return x < y ? x : y; }
19+
template <class T>
20+
using P = pair<T, T>;
21+
template <class T>
22+
P<T> PAdd(P<T> x, P<T> y) { return P<T>{x.first + y.first, x.second + y.second}; }
23+
template <class T>
24+
P<T> FPAdd(T f, P<T> x) { return P<T>{x.first, x.second + x.first * f}; }
25+
template <class T>
26+
P<T> PZero() { return P<T>{T{}, T{}}; }
27+
template <class T>
28+
vector<P<T>> InitPair(const vector<T>& a) {
29+
vector<P<T>> v(a.size());
30+
for (int i = 0; i < (int)v.size(); i++) v[i] = P<T>{1, a[i]};
31+
return v;
32+
}
33+
template <class T>
34+
struct LazySegmentTreeAddSum : LazySegmentTree<P<T>, PAdd<T>, PZero<T>, T, FPAdd<T>, Add<T>, Zero<T>> {
35+
using base = LazySegmentTree<P<T>, PAdd<T>, PZero<T>, T, PAdd<T>, Add<T>, Zero<T>>;
36+
LazySegmentTreeAddSum(int n) : base(vector<P<T>>(n, PZero<T>())) {}
37+
LazySegmentTreeAddSum(const vector<T>& a) : base(InitPair(a)) {}
38+
};
39+
template <class T>
40+
struct LazySegmentTreeMulSum : LazySegmentTree<T, Add<T>, Zero<T>, T, Mul<T>, Mul<T>, One<T>> {
41+
using base = LazySegmentTree<T, Add<T>, Zero<T>, T, Mul<T>, Mul<T>, One<T>>;
42+
LazySegmentTreeMulSum(int n) : base(vector<T>(n, Zero<T>())) {}
43+
LazySegmentTreeMulSum(const vector<T>& a) : base(a) {}
44+
};
45+
}; // namespace LazySegmentTreeUtil
46+
using LazySegmentTreeUtil::LazySegmentTreeAddSum;
47+
using LazySegmentTreeUtil::LazySegmentTreeMulSum;
48+
/**
49+
* @brief よく使う Lazy Segment Tree
50+
* @docs docs/segment-tree/lazy-segment-tree-util.md
51+
*/

0 commit comments

Comments
 (0)