Skip to content

Commit 6de3e5c

Browse files
refactor: 0-index to 1-index (#48)
1 parent 7051494 commit 6de3e5c

16 files changed

Lines changed: 219 additions & 223 deletions

src/1-ds/ds_fenwick.cpp

Lines changed: 38 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,49 @@
22

33
// what: maintain prefix sums with point updates and range sum queries.
44
// time: build O(n), update/query O(log n); memory: O(n)
5-
// constraint: 0-indexed; kth needs all values >= 0.
5+
// constraint: 1-indexed [1, n]; a[0] unused; kth needs all values >= 0.
66
// usage: fenwick fw; fw.build(a); fw.add(p, x); fw.sum(l, r); fw.kth(k);
77
struct fenwick {
88
int n;
99
vector<ll> a, t;
1010
void init(int n_) {
1111
// goal: allocate arrays for size n.
1212
n = n_;
13-
a.assign(n, 0);
14-
t.assign(n, 0);
13+
a.assign(n + 1, 0);
14+
t.assign(n + 1, 0);
1515
}
1616
void build(const vector<ll> &v) {
1717
// goal: build fenwick in O(n) from initial array.
18-
n = sz(v);
18+
n = sz(v) - 1;
1919
a = v;
20-
t.assign(n, 0);
21-
for (int i = 0; i < n; i++) {
22-
t[i] += a[i];
23-
int j = i | (i + 1);
24-
if (j < n) t[j] += t[i];
20+
t = a;
21+
for (int i = 1; i <= n; i++) {
22+
int j = i + (i & -i);
23+
if (j <= n) t[j] += t[i];
2524
}
2625
}
2726
void add(int p, ll val) {
2827
// goal: a[p] += val.
2928
a[p] += val;
30-
for (int i = p; i < n; i |= i + 1) t[i] += val;
29+
for (int i = p; i <= n; i += i & -i) t[i] += val;
3130
}
3231
void set(int p, ll val) { add(p, val - a[p]); }
3332
ll sum(int x) const {
34-
// result: prefix sum on [0..x].
33+
// result: prefix sum on [1..x].
3534
ll ret = 0;
36-
for (int i = x; i >= 0; i = (i & (i + 1)) - 1) ret += t[i];
35+
for (int i = x; i > 0; i -= i & -i) ret += t[i];
3736
return ret;
3837
}
39-
ll sum(int l, int r) const { return sum(r) - (l ? sum(l - 1) : 0); }
38+
ll sum(int l, int r) const { return sum(r) - sum(l - 1); }
4039
int kth(ll k) const {
4140
// result: smallest idx with prefix sum >= k.
42-
assert(k > 0 && sum(n - 1) >= k);
43-
int idx = -1;
41+
assert(k > 0 && sum(n) >= k);
42+
int idx = 0;
4443
int bit = 1;
45-
while (bit < n) bit <<= 1;
44+
while (bit <= n) bit <<= 1;
4645
for (; bit; bit >>= 1) {
4746
int nxt = idx + bit;
48-
if (nxt < n && t[nxt] < k) {
47+
if (nxt <= n && t[nxt] < k) {
4948
idx = nxt;
5049
k -= t[nxt];
5150
}
@@ -81,53 +80,50 @@ struct fenw_range { // 1-indexed
8180

8281
// what: 2D point updates with axis-aligned rectangle sum queries.
8382
// time: build O(n m), update/query O(log n log m); memory: O(n m)
84-
// constraint: 0-indexed; no bounds check.
83+
// constraint: 1-indexed [1..n] x [1..m]; a[0][*], a[*][0] unused; no bounds check.
8584
// usage: fenw_2d fw; fw.build(a); fw.add(x, y, v); fw.sum(x1, y1, x2, y2);
86-
struct fenw_2d { // 0-indexed
85+
struct fenw_2d { // 1-indexed
8786
int n, m;
8887
vector<vector<ll>> a, t;
8988
void init(int n_, int m_) {
9089
// goal: allocate arrays for n x m.
9190
n = n_, m = m_;
92-
a.assign(n, vector<ll>(m, 0));
93-
t.assign(n, vector<ll>(m, 0));
91+
a.assign(n + 1, vector<ll>(m + 1, 0));
92+
t.assign(n + 1, vector<ll>(m + 1, 0));
9493
}
9594
void build(const vector<vector<ll>> &v) {
9695
// goal: build 2D fenwick in O(n*m).
97-
n = sz(v);
98-
m = n ? sz(v[0]) : 0;
96+
n = sz(v) - 1;
97+
m = n ? sz(v[1]) - 1 : 0;
9998
a = v;
100-
t.assign(n, vector<ll>(m, 0));
101-
for (int i = 0; i < n; i++) {
102-
for (int j = 0; j < m; j++) {
103-
t[i][j] += a[i][j];
104-
int ni = i | (i + 1), nj = j | (j + 1);
105-
if (ni < n) t[ni][j] += t[i][j];
106-
if (nj < m) t[i][nj] += t[i][j];
107-
if (ni < n && nj < m) t[ni][nj] -= t[i][j];
99+
t = a;
100+
for (int i = 1; i <= n; i++)
101+
for (int j = 1; j <= m; j++) {
102+
int nj = j + (j & -j);
103+
if (nj <= m) t[i][nj] += t[i][j];
104+
}
105+
for (int j = 1; j <= m; j++)
106+
for (int i = 1; i <= n; i++) {
107+
int ni = i + (i & -i);
108+
if (ni <= n) t[ni][j] += t[i][j];
108109
}
109-
}
110110
}
111111
void add(int x, int y, ll val) {
112112
// goal: a[x][y] += val.
113113
a[x][y] += val;
114-
for (int i = x; i < n; i |= i + 1)
115-
for (int j = y; j < m; j |= j + 1) t[i][j] += val;
114+
for (int i = x; i <= n; i += i & -i)
115+
for (int j = y; j <= m; j += j & -j) t[i][j] += val;
116116
}
117117
void set(int x, int y, ll val) { add(x, y, val - a[x][y]); }
118118
ll sum(int x, int y) const {
119-
// result: sum over rectangle [0..x] x [0..y].
119+
// result: sum over rectangle [1..x] x [1..y].
120120
ll ret = 0;
121-
for (int i = x; i >= 0; i = (i & (i + 1)) - 1)
122-
for (int j = y; j >= 0; j = (j & (j + 1)) - 1) ret += t[i][j];
121+
for (int i = x; i > 0; i -= i & -i)
122+
for (int j = y; j > 0; j -= j & -j) ret += t[i][j];
123123
return ret;
124124
}
125125
ll sum(int x1, int y1, int x2, int y2) const {
126126
// result: sum over rectangle [x1..x2] x [y1..y2].
127-
ll ret = sum(x2, y2);
128-
if (x1) ret -= sum(x1 - 1, y2);
129-
if (y1) ret -= sum(x2, y1 - 1);
130-
if (x1 && y1) ret += sum(x1 - 1, y1 - 1);
131-
return ret;
127+
return sum(x2, y2) - sum(x1 - 1, y2) - sum(x2, y1 - 1) + sum(x1 - 1, y1 - 1);
132128
}
133129
};

src/1-ds/ds_merge_seg.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@ constexpr int MAX_MST = 1 << 17;
33

44
// what: static range count queries by storing sorted lists on a segment tree.
55
// time: build O(n log n), query O(log^2 n); memory: O(n log n)
6-
// constraint: MAX_MST >= n; values fit in int; 0-indexed [l, r]; build once.
6+
// constraint: MAX_MST >= n; values fit in int; 1-indexed [1..n]; build once.
77
// usage: merge_seg st; st.build(a); st.query(l, r, k);
88
struct merge_seg {
99
vector<int> t[MAX_MST << 1];
1010
void build(const vector<int> &a) {
1111
// goal: build sorted lists for each node.
12-
for (int i = 0; i < sz(a); i++)
13-
t[i + MAX_MST].push_back(a[i]);
12+
for (int i = 1; i < sz(a); i++)
13+
t[i + MAX_MST - 1].push_back(a[i]);
1414
for (int i = MAX_MST - 1; i >= 1; i--) {
1515
t[i].resize(sz(t[i << 1]) + sz(t[i << 1 | 1]));
1616
merge(all(t[i << 1]), all(t[i << 1 | 1]), t[i].begin());
1717
}
1818
}
19-
int query(int l, int r, int k, int v = 1, int nl = 0, int nr = MAX_MST - 1) const {
19+
int query(int l, int r, int k, int v = 1, int nl = 1, int nr = MAX_MST) const {
2020
// result: count of elements > k in [l, r].
2121
if (nr < l || r < nl) return 0;
2222
if (l <= nl && nr <= r)
@@ -28,22 +28,22 @@ struct merge_seg {
2828

2929
// what: iterative merge sort tree for static range count queries.
3030
// time: build O(n log n), query O(log^2 n); memory: O(n log n)
31-
// constraint: MAX_MST >= n; values fit in int; 0-indexed [l, r]; build once.
31+
// constraint: MAX_MST >= n; values fit in int; 1-indexed [1..n]; build once.
3232
// usage: merge_seg_it st; st.build(a); st.query(l, r, k);
3333
struct merge_seg_it {
3434
vector<int> t[MAX_MST << 1];
3535
void build(const vector<int> &a) {
3636
// goal: build sorted lists for each node.
37-
for (int i = 0; i < sz(a); i++)
38-
t[i + MAX_MST].push_back(a[i]);
37+
for (int i = 1; i < sz(a); i++)
38+
t[i + MAX_MST - 1].push_back(a[i]);
3939
for (int i = MAX_MST - 1; i >= 1; i--) {
4040
t[i].resize(sz(t[i << 1]) + sz(t[i << 1 | 1]));
4141
merge(all(t[i << 1]), all(t[i << 1 | 1]), t[i].begin());
4242
}
4343
}
4444
int query(int l, int r, int k) const {
4545
// result: count of elements > k in [l, r].
46-
l += MAX_MST, r += MAX_MST;
46+
l += MAX_MST - 1, r += MAX_MST - 1;
4747
int ret = 0;
4848
while (l <= r) {
4949
if (l & 1) ret += int(t[l].end() - upper_bound(all(t[l]), k)), l++;

src/1-ds/ds_segtree.cpp

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,26 @@ struct seg_tree {
3232

3333
// what: iterative segment tree for point update and range sum.
3434
// time: build O(n), update/query O(log n); memory: O(n)
35-
// constraint: 0-indexed [l, r).
35+
// constraint: 1-indexed [1, n]; a[0] unused.
3636
// usage: seg_tree_it st; st.build(a); st.set(p, v); st.query(l, r);
37-
struct seg_tree_it { // 0-indexed
37+
struct seg_tree_it { // 1-indexed
3838
int n;
3939
vector<ll> t;
4040
void build(const vector<ll> &a) {
41-
// goal: build tree from 0-indexed array.
42-
n = sz(a);
41+
// goal: build tree from 1-indexed array.
42+
n = sz(a) - 1;
4343
t.assign(2 * n, 0);
44-
for (int i = 0; i < n; i++) t[n + i] = a[i];
44+
for (int i = 1; i <= n; i++) t[n + i - 1] = a[i];
4545
for (int i = n - 1; i >= 1; i--) t[i] = t[i << 1] + t[i << 1 | 1];
4646
}
4747
void set(int p, ll val) {
4848
// goal: set a[p] = val.
49-
for (t[p += n] = val; p > 1; p >>= 1) t[p >> 1] = t[p] + t[p ^ 1];
49+
for (t[p += n - 1] = val; p > 1; p >>= 1) t[p >> 1] = t[p] + t[p ^ 1];
5050
}
5151
ll query(int l, int r) const {
52-
// result: sum on [l, r).
52+
// result: sum on [l, r].
5353
ll ret = 0;
54-
for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
54+
for (l += n - 1, r += n; l < r; l >>= 1, r >>= 1) {
5555
if (l & 1) ret += t[l++];
5656
if (r & 1) ret += t[--r];
5757
}
@@ -183,18 +183,18 @@ struct seg_sparse {
183183

184184
// what: 2D point updates with rectangle sum queries on a square grid.
185185
// time: build O(n^2), update/query O(log^2 n); memory: O(n^2)
186-
// constraint: 0-indexed square n x n.
186+
// constraint: 1-indexed square [1..n] x [1..n]; a[0][*], a[*][0] unused.
187187
// usage: seg_2d st; st.build(a); st.set(x, y, v); st.query(x1, x2, y1, y2);
188-
struct seg_2d { // 0-indexed
188+
struct seg_2d { // 1-indexed
189189
int n;
190190
vector<vector<ll>> t;
191191
void build(const vector<vector<ll>> &a) {
192192
// goal: build 2D tree from initial grid.
193-
n = sz(a);
193+
n = sz(a) - 1;
194194
t.assign(2 * n, vector<ll>(2 * n, 0));
195-
for (int i = 0; i < n; i++)
196-
for (int j = 0; j < n; j++)
197-
t[i + n][j + n] = a[i][j];
195+
for (int i = 1; i <= n; i++)
196+
for (int j = 1; j <= n; j++)
197+
t[i + n - 1][j + n - 1] = a[i][j];
198198
for (int i = n; i < 2 * n; i++)
199199
for (int j = n - 1; j > 0; j--)
200200
t[i][j] = t[i][j << 1] + t[i][j << 1 | 1];
@@ -204,6 +204,7 @@ struct seg_2d { // 0-indexed
204204
}
205205
void set(int x, int y, ll val) {
206206
// goal: set a[x][y] = val.
207+
x--, y--;
207208
t[x + n][y + n] = val;
208209
for (int j = y + n; j > 1; j >>= 1)
209210
t[x + n][j >> 1] = t[x + n][j] + t[x + n][j ^ 1];
@@ -222,6 +223,7 @@ struct seg_2d { // 0-indexed
222223
}
223224
ll query(int x1, int x2, int y1, int y2) const {
224225
// result: sum on rectangle [x1..x2] x [y1..y2].
226+
x1--, x2--, y1--, y2--;
225227
ll ret = 0;
226228
for (x1 += n, x2 += n + 1; x1 < x2; x1 >>= 1, x2 >>= 1) {
227229
if (x1 & 1) ret += qry1d(x1++, y1, y2);
@@ -233,21 +235,21 @@ struct seg_2d { // 0-indexed
233235

234236
// what: 2D segment tree with coordinate compression for sparse updates/queries.
235237
// time: prep O(q log q), update/query O(log^2 n); memory: O(q log q)
236-
// constraint: call mark_set/mark_qry first, then prep, then set/query.
238+
// constraint: x is 1-indexed [1..n]; y is coordinate value; call mark_set/mark_qry first, then prep, then set/query.
237239
// usage: seg2d_comp st(n); st.mark_set(x, y); st.mark_qry(x1, x2, y1, y2); st.prep(); st.set(x, y, v); st.query(x1, x2, y1, y2);
238-
struct seg2d_comp { // 0-indexed
240+
struct seg2d_comp { // x: 1-indexed
239241
int n;
240242
vector<vector<ll>> a;
241243
vector<vector<int>> used;
242244
unordered_map<ll, ll> mp;
243245
seg2d_comp(int n) : n(n), a(2 * n), used(2 * n) {}
244246
void mark_set(int x, int y) {
245247
// goal: record y-coordinates that will be updated.
246-
for (x += n; x >= 1; x >>= 1) used[x].push_back(y);
248+
for (x += n - 1; x >= 1; x >>= 1) used[x].push_back(y);
247249
}
248250
void mark_qry(int x1, int x2, int y1, int y2) {
249251
// goal: record y-coordinates needed for queries.
250-
for (x1 += n, x2 += n + 1; x1 < x2; x1 >>= 1, x2 >>= 1) {
252+
for (x1 += n - 1, x2 += n; x1 < x2; x1 >>= 1, x2 >>= 1) {
251253
if (x1 & 1) {
252254
used[x1].push_back(y1);
253255
used[x1++].push_back(y2);
@@ -274,7 +276,7 @@ struct seg2d_comp { // 0-indexed
274276
ll k = (ll)x << 32 | (unsigned)y;
275277
ll d = v - mp[k];
276278
mp[k] = v;
277-
for (x += n; x >= 1; x >>= 1) {
279+
for (x += n - 1; x >= 1; x >>= 1) {
278280
int i = lower_bound(all(used[x]), y) - used[x].begin() + sz(used[x]);
279281
for (a[x][i] += d; i > 1; i >>= 1)
280282
a[x][i >> 1] = a[x][i] + a[x][i ^ 1];
@@ -294,7 +296,7 @@ struct seg2d_comp { // 0-indexed
294296
ll query(int x1, int x2, int y1, int y2) const {
295297
// result: sum on rectangle [x1..x2] x [y1..y2].
296298
ll ret = 0;
297-
for (x1 += n, x2 += n + 1; x1 < x2; x1 >>= 1, x2 >>= 1) {
299+
for (x1 += n - 1, x2 += n; x1 < x2; x1 >>= 1, x2 >>= 1) {
298300
if (x1 & 1) ret += qry1d(x1++, y1, y2);
299301
if (x2 & 1) ret += qry1d(--x2, y1, y2);
300302
}

src/4-optimizations/flow_dinic.cpp

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

33
// what: compute maximum flow in a directed graph (Dinic).
44
// time: O(E V^2) worst; memory: O(E)
5-
// constraint: 0-based; cap >= 0.
5+
// constraint: 1-indexed [1..n]; cap >= 0.
66
// usage: dinic mf(n); mf.add_edge(u, v, cap); ll f = mf.max_flow(s, t);
77
struct dinic {
88
static constexpr ll INF = (1LL << 62);
@@ -22,7 +22,7 @@ struct dinic {
2222
dinic(int n = 0) { init(n); }
2323
void init(int n_) {
2424
n = n_;
25-
g.assign(n, {});
25+
g.assign(n + 1, {});
2626
}
2727
edge_ref add_edge(int u, int v, ll cap) {
2828
// goal: add forward + reverse edge
@@ -47,7 +47,7 @@ struct dinic {
4747

4848
bool bfs(int s, int t) {
4949
// goal: build level graph
50-
level.assign(n, -1);
50+
level.assign(n + 1, -1);
5151
queue<int> q;
5252
level[s] = 0;
5353
q.push(s);
@@ -80,7 +80,7 @@ struct dinic {
8080
if (s == t) return 0; // edge: no flow needed
8181
ll flow = 0;
8282
while (flow < limit && bfs(s, t)) {
83-
work.assign(n, 0);
83+
work.assign(n + 1, 0);
8484
while (flow < limit) {
8585
ll pushed = dfs(s, t, limit - flow);
8686
if (pushed == 0) break;
@@ -93,7 +93,7 @@ struct dinic {
9393

9494
// what: find feasible max flow with lower/upper bounds via transformation.
9595
// time: dominated by dinic; memory: O(E)
96-
// constraint: 0-based; 0 <= lo <= hi; single-use (call init(n) to reuse).
96+
// constraint: 1-indexed [1..n]; 0 <= lo <= hi; single-use (call init(n) to reuse).
9797
// usage: lr_dinic f(n); f.add_edge(u, v, lo, hi); auto [ok, fl] = f.max_flow(s, t);
9898
struct lr_dinic {
9999
static constexpr ll INF = dinic::INF;
@@ -112,7 +112,7 @@ struct lr_dinic {
112112
void init(int n_) {
113113
n = n_;
114114
mf.init(n + 2);
115-
demand.assign(n, 0);
115+
demand.assign(n + 1, 0);
116116
edges.clear();
117117
}
118118
int add_edge(int u, int v, ll lo, ll hi) {
@@ -129,8 +129,8 @@ struct lr_dinic {
129129
ll add_demands(vector<dinic::edge_ref> &aux) {
130130
// goal: connect ss/tt for feasible circulation
131131
ll total = 0;
132-
int ss = n, tt = n + 1;
133-
for (int i = 0; i < n; i++) {
132+
int ss = n + 1, tt = n + 2;
133+
for (int i = 1; i <= n; i++) {
134134
if (demand[i] > 0) {
135135
aux.push_back(mf.add_edge(ss, i, demand[i]));
136136
total += demand[i];
@@ -145,7 +145,7 @@ struct lr_dinic {
145145
vector<dinic::edge_ref> aux;
146146
aux.reserve(n);
147147
ll total = add_demands(aux);
148-
int ss = n, tt = n + 1;
148+
int ss = n + 1, tt = n + 2;
149149
ll flow = mf.max_flow(ss, tt);
150150
for (auto ref : aux) mf.clear_edge(ref);
151151
return flow == total;
@@ -154,7 +154,7 @@ struct lr_dinic {
154154
if (s == t) return {feasible(), 0}; // edge: trivial s == t
155155
vector<dinic::edge_ref> aux;
156156
aux.reserve(n + 1);
157-
int ss = n, tt = n + 1;
157+
int ss = n + 1, tt = n + 2;
158158
auto ts = mf.add_edge(t, s, INF);
159159
ll total = add_demands(aux);
160160
ll flow = mf.max_flow(ss, tt);

0 commit comments

Comments
 (0)