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
5 changes: 3 additions & 2 deletions content/contest/template.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ void solve() {
signed main() {
cin.tie(nullptr)->sync_with_stdio(false);
int t = 1;
// cin >> t;
while (t--) solve();
cin >> t;
while (t--)
solve();
return 0;
}

Expand Down
5 changes: 4 additions & 1 deletion content/data-structures/DSU.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/**
* Author: Ramez
* Author: Lukas Polacek
* Date: 2009-10-26
* License: CC0
* Source: folklore
* Description: Disjoint-set data structure.
* Time: $O(\alpha(N))$
*/
Expand Down
71 changes: 33 additions & 38 deletions content/data-structures/Fenwick2dXor.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,54 +4,49 @@
* Time: $O(\log N \cdot \log M)$.
*/
#pragma once
struct Fenwick2DAdd {

struct Fenwick2DXOR {
int n, m;
vector<vi> T1, T2, T3, T4;
vector<vi> bit[2][2];

Fenwick2DAdd(int _n, int _m)
: n(_n), m(_m),
T1(n+1, vi(m+1)),
T2(n+1, vi(m+1)),
T3(n+1, vi(m+1)),
T4(n+1, vi(m+1))
{}
Fenwick2DXOR(int _n, int _m) : n(_n), m(_m) {
for (int px = 0; px < 2; ++px)
for (int py = 0; py < 2; ++py)
bit[px][py].assign(n+2, vi(m+2, 0));
}

void add(vector<vi>& t, int x, int y, int v) {
void pointXOR(int x, int y, int v) {
for (int i = x; i <= n; i += i & -i)
for (int j = y; j <= m; j += j & -j)
t[i][j] += v;
bit[x&1][y&1][i][j] ^= v;
}

void rangeAdd(int x, int y, int v) {
add(T1, x, y, v);
add(T2, x, y, v * (y - 1));
add(T3, x, y, v * (x - 1));
add(T4, x, y, v * (x - 1) * (y - 1));
void rangeXOR(int x1, int y1, int x2, int y2, int v) {
if (x1 > x2 || y1 > y2) return;
auto upd = [&](int x, int y){ if (x > 0 && y > 0) pointXOR(x, y, v); };
upd(x1, y1);
upd(x2 + 1, y1);
upd(x1, y2 + 1);
upd(x2 + 1, y2 + 1);
}

void rangeUpdate(int x1, int y1, int x2, int y2, int val) {
rangeAdd(x1, y1, val);
rangeAdd(x1, y2 + 1, -val);
rangeAdd(x2 + 1, y1, -val);
rangeAdd(x2 + 1, y2 + 1, val);
}

int prefixSum(int x, int y) const {
int s1 = 0, s2 = 0, s3 = 0, s4 = 0;
int prefixXOR(int x, int y) {
if (x <= 0 || y <= 0) return 0;
int res = 0;
int px = x & 1, py = y & 1;
for (int i = x; i > 0; i -= i & -i)
for (int j = y; j > 0; j -= j & -j) {
s1 += T1[i][j];
s2 += T2[i][j];
s3 += T3[i][j];
s4 += T4[i][j];
}
return s1 * x * y - s2 * x - s3 * y + s4;
for (int j = y; j > 0; j -= j & -j)
res ^= bit[px][py][i][j];
return res;
}

int rangeQuery(int x1, int y1, int x2, int y2) const {
return prefixSum(x2, y2)
- prefixSum(x1 - 1, y2)
- prefixSum(x2, y1 - 1)
+ prefixSum(x1 - 1, y1 - 1);
int rangeQuery(int x1, int y1, int x2, int y2) {
int res = 0;
res ^= prefixXOR(x2, y2);
res ^= prefixXOR(x1-1, y2);
res ^= prefixXOR(x2, y1-1);
res ^= prefixXOR(x1-1, y1-1);
return res;
}
};
};

71 changes: 71 additions & 0 deletions content/data-structures/MOs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* Author: Mohamed El-Sayed
* Description: Mo's algorithm (offline) for answering range‐distinct queries.
Sorts queries into sqrt-blocks by L, then R, and moves two pointers
to maintain current range, updating a frequency table.
* Time: O((N + Q)*sqrt(N)) Memory O(N + Q).
* Status: stress-tested
*/

struct Query {
int l, r, idx;
bool operator<(const Query &other) const {
const int BLOCK = 450; // sqrt(max(N))
int b1 = l / BLOCK;
int b2 = other.l / BLOCK;
if (b1 != b2) return b1 < b2; // different block by L
return r < other.r; // same block, sort by R
}
};

void solve() {
fastio();
int n, q;
cin >> n >> q;
vector<int> a(n);
for (int &x : a) cin >> x;

// Read and store offline queries
vector<Query> queries(q);
for (int i = 0; i < q; ++i) {
int l, r;
cin >> l >> r;
queries[i] = {l - 1, r - 1, i}; // convert to 0-based
}

// Sort queries by Mo's ordering
sort(queries.begin(), queries.end());

// Frequency table, current distinct count, current range [curL..curR]
const int MAXV = 1'000'005;
vector<int> freq(MAXV, 0);
int distinct = 0, curL = 0, curR = -1;
vector<int> ans(q);

// Process each query by expanding/shrinking [curL..curR]
for (auto &qr : queries) {
// Expand right end
while (curR < qr.r) {
if (++freq[a[++curR]] == 1) ++distinct;
}
// Shrink right end
while (curR > qr.r) {
if (--freq[a[curR--]] == 0) --distinct;
}
// Shrink left end
while (curL < qr.l) {
if (--freq[a[curL++]] == 0) --distinct;
}
// Expand left end
while (curL > qr.l) {
if (++freq[a[--curL]] == 1) ++distinct;
}
// Record answer for this query
ans[qr.idx] = distinct;
}

// Output all answers in original order
for (int x : ans) {
cout << x << '\n';
}
}
85 changes: 85 additions & 0 deletions content/data-structures/SQRTD.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@

/**
* Author: Mohamed El-Sayed
* Description: Square‐root decomposition for range sum queries with point updates.
Preprocesses the array into blocks of size ~sqrt(n), maintaining the sum of each block.
query(l, r): returns the sum of arr[l..r] in O(sqrt(n)) time.
update(idx, val): updates arr[idx] to val and adjusts the corresponding block sum in O(1).
When to use:
- You have an array of size n (up to $10^5$) with mixed range‐sum queries and point updates.
- You need better performance than O(n) per operation but segment trees are overkill.
* Time: O(sqrt(n)) per query, O(1) per update.
* Status: stress-tested
*/
#include <bits/stdc++.h>
using namespace std;

using vi = vector<int>;

int n, q, SQ;
vi arr, blkSum;

// Build block sums from the initial array in O(n)
void preProcess() {
// For each element, add it to its block's sum
for (int i = 0; i < n; ++i) {
int blk = i / SQ;
blkSum[blk] += arr[i];
}
}

// Query the sum in the interval [l, r] in O(sqrt(n))
int query(int l, int r) {
int ans = 0;
// Process elements until we reach block boundary or exceed r
while (l <= r) {
// If l is at the start of a block and the whole block lies within [l, r]
if (l % SQ == 0 && l + SQ - 1 <= r) {
ans += blkSum[l / SQ];
l += SQ;
} else {
// Otherwise, take the single element
ans += arr[l];
++l;
}
}
return ans;
}

// Point update: set arr[idx] = val in O(1)
void update(int idx, int val) {
int blk = idx / SQ;
// Remove old value from block sum and add new value
blkSum[blk] -= arr[idx];
arr[idx] = val;
blkSum[blk] += val;
}

void solve() {
// Read array size and number of operations
cin >> n >> q;
arr.resize(n);
cin >> arr;

// Determine block size and initialize block sums
SQ = ceil(sqrt(n));
blkSum.assign((n + SQ - 1) / SQ, 0);

preProcess();

while (q--) {
int op;
cin >> op;
if (op == 1) {
// Update operation: 1 pos val
int pos, val;
cin >> pos >> val;
update(pos - 1, val);
} else {
// Query operation: 2 l r
int l, r;
cin >> l >> r;
cout << query(l - 1, r - 1) << "\n";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
#pragma once

template<class T>
struct PrefixSum2D {
struct SubMatrix {
vector<vector<T>> p;
PrefixSum2D(vector<vector<T>>& v) {
int R = v.size(), C = v[0].size();
p.assign(R + 1, vector<T>(C + 1));
for (int r = 0; r < R; r++) for (int c = 0; c < C; c++)
p[r + 1][c + 1] = v[r][c] + p[r][c + 1] + p[r + 1][c] - p[r][c];
SubMatrix(vector<vector<T>>& v) {
int R = sz(v), C = sz(v[0]);
p.assign(R+1, vector<T>(C+1));
rep(r,0,R) rep(c,0,C)
p[r+1][c+1] = v[r][c] + p[r][c+1] + p[r+1][c] - p[r][c];
}
T sum(int u, int l, int d, int r) {
return p[d][r] - p[d][l] - p[u][r] + p[u][l];
Expand Down
70 changes: 0 additions & 70 deletions content/data-structures/Trie.cpp

This file was deleted.

6 changes: 4 additions & 2 deletions content/data-structures/chapter.tex
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ \chapter{Data structures}
\kactlimport{HashMap.h}
\kactlimport{DSU.h}
\kactlimport{DSURollback.h}
\kactlimport{PrefixSum2D.h}
\kactlimport{SubMatrix.h}
\kactlimport{Matrix.h}
\kactlimport{LineContainer.h}
\kactlimport{Treap.h}
\kactlimport{RMQ.h}
\kactlimport{MoQueries.h}
\kactlimport{MergeSortTree.h}
\kactlimport{Trie.cpp}
% \kactlimport{Trie.cpp}
\kactlimport{BinaryTrie.cpp}
\kactlimport{SQRTD.cpp}
\kactlimport{MOs.cpp}


Loading