fork download
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. using ll = long long;
  5.  
  6. // ===================================================================
  7. // 1) Fenwick Tree (Binary Indexed Tree) – Basic Utility
  8. // Supports point updates and prefix sums.
  9. // Used in many offline algorithms.
  10. // ===================================================================
  11.  
  12. struct Fenwick {
  13. int n;
  14. vector<int> bit;
  15. Fenwick(int n) : n(n), bit(n + 1, 0) {}
  16.  
  17. void add(int idx, int delta) {
  18. for (; idx <= n; idx += idx & -idx)
  19. bit[idx] += delta;
  20. }
  21.  
  22. int sumPrefix(int idx) const {
  23. int res = 0;
  24. for (; idx > 0; idx -= idx & -idx)
  25. res += bit[idx];
  26. return res;
  27. }
  28.  
  29. int rangeSum(int l, int r) const {
  30. if (l > r) return 0;
  31. return sumPrefix(r) - sumPrefix(l - 1);
  32. }
  33. };
  34.  
  35. // ===================================================================
  36. // 2) Offline Range Sum Queries (no updates)
  37. // Given an array and many queries (L, R) – answer sum of a[L..R].
  38. // This is trivial with prefix sums, but we show the offline approach
  39. // using BIT as a pattern for more complex problems.
  40. // ===================================================================
  41.  
  42. vector<ll> offlineRangeSum(const vector<ll>& arr,
  43. const vector<pair<int,int>>& queries) {
  44. int n = arr.size();
  45. vector<ll> pref(n + 1, 0);
  46. for (int i = 0; i < n; ++i) pref[i + 1] = pref[i] + arr[i];
  47. vector<ll> ans(queries.size());
  48. for (size_t i = 0; i < queries.size(); ++i) {
  49. int l = queries[i].first, r = queries[i].second;
  50. ans[i] = pref[r + 1] - pref[l];
  51. }
  52. return ans;
  53. }
  54.  
  55. // ===================================================================
  56. // 3) Offline Counting of Distinct Elements in Range Queries
  57. // Problem: Given an array a[1..n] and Q queries (L, R),
  58. // count the number of distinct values in a[L..R].
  59. // Idea: Sort queries by R, maintain last occurrence of each value,
  60. // and use BIT to mark positions of last occurrences.
  61. // ===================================================================
  62.  
  63. vector<int> countDistinctInRange(const vector<int>& a,
  64. const vector<pair<int,int>>& queries) {
  65. int n = a.size();
  66. int q = queries.size();
  67. vector<int> ans(q);
  68. vector<vector<pair<int,int>>> byRight(n + 1); // queries grouped by right endpoint
  69. for (int i = 0; i < q; ++i) {
  70. int l = queries[i].first, r = queries[i].second;
  71. byRight[r].push_back({l, i});
  72. }
  73.  
  74. Fenwick bit(n);
  75. unordered_map<int, int> last; // value -> last position seen
  76.  
  77. for (int r = 1; r <= n; ++r) {
  78. int val = a[r - 1];
  79. if (last.count(val)) {
  80. bit.add(last[val], -1);
  81. }
  82. last[val] = r;
  83. bit.add(r, 1);
  84.  
  85. for (auto &p : byRight[r]) {
  86. int l = p.first, idx = p.second;
  87. ans[idx] = bit.rangeSum(l, r);
  88. }
  89. }
  90. return ans;
  91. }
  92.  
  93. // ===================================================================
  94. // 4) Count Subarrays with Sum in [L, R] (works for negative numbers)
  95. // Idea: prefix sums. For each prefix sum P[i], we need the number of
  96. // earlier prefix sums P[j] (j < i) with L <= P[i] - P[j] <= R.
  97. // Rearrange: P[i] - R <= P[j] <= P[i] - L.
  98. // Process i from 1..n, coordinate compress all prefix sums,
  99. // use BIT to count how many previous prefixes fall in that range.
  100. // ===================================================================
  101.  
  102. ll countSubarraysSumInRange(const vector<int>& nums, ll L, ll R) {
  103. int n = nums.size();
  104. vector<ll> pref(n + 1, 0);
  105. for (int i = 0; i < n; ++i) pref[i + 1] = pref[i] + nums[i];
  106.  
  107. // coordinate compression of all prefix sums
  108. vector<ll> comp = pref;
  109. sort(comp.begin(), comp.end());
  110. comp.erase(unique(comp.begin(), comp.end()), comp.end());
  111.  
  112. auto getIdx = [&](ll x) {
  113. return int(lower_bound(comp.begin(), comp.end(), x) - comp.begin()) + 1;
  114. };
  115.  
  116. Fenwick bit(comp.size());
  117. ll ans = 0;
  118. bit.add(getIdx(pref[0]), 1); // prefix 0
  119.  
  120. for (int i = 1; i <= n; ++i) {
  121. // need pref[j] in [pref[i]-R, pref[i]-L]
  122. ll lo = pref[i] - R;
  123. ll hi = pref[i] - L;
  124. int left = int(lower_bound(comp.begin(), comp.end(), lo) - comp.begin()) + 1;
  125. int right = int(upper_bound(comp.begin(), comp.end(), hi) - comp.begin()); // exclusive -> index (1‑based) of first > hi
  126. if (left <= right) {
  127. ans += bit.rangeSum(left, right);
  128. }
  129. bit.add(getIdx(pref[i]), 1);
  130. }
  131. return ans;
  132. }
  133.  
  134. // ===================================================================
  135. // 5) Mo's Algorithm – for Range Queries
  136. // Example: answer sum of distinct elements in range, or frequency
  137. // queries. This template shows a generic Mo framework.
  138. // Usage: define add() and remove() functions, and compute answer
  139. // when moving pointers.
  140. // Complexity: O((N + Q) * sqrt(N))
  141. // ===================================================================
  142.  
  143. struct MoQuery {
  144. int l, r, idx, block;
  145. };
  146.  
  147. // Example: count number of distinct elements in [l,r] using Mo
  148. vector<int> moDistinct(const vector<int>& a, const vector<pair<int,int>>& queries) {
  149. int n = a.size();
  150. int q = queries.size();
  151. int blockSize = max(1, (int)sqrt(n));
  152.  
  153. vector<MoQuery> qs(q);
  154. for (int i = 0; i < q; ++i) {
  155. qs[i].l = queries[i].first;
  156. qs[i].r = queries[i].second;
  157. qs[i].idx = i;
  158. qs[i].block = qs[i].l / blockSize;
  159. }
  160.  
  161. sort(qs.begin(), qs.end(), [](const MoQuery& a, const MoQuery& b) {
  162. if (a.block != b.block) return a.block < b.block;
  163. if (a.block & 1) return a.r > b.r; // odd-even optimization
  164. return a.r < b.r;
  165. });
  166.  
  167. vector<int> ans(q);
  168. vector<int> freq(*max_element(a.begin(), a.end()) + 1, 0);
  169. int curL = 1, curR = 0; // 1-indexed, inclusive
  170. int distinct = 0;
  171.  
  172. auto add = [&](int pos) {
  173. int val = a[pos - 1];
  174. if (freq[val] == 0) distinct++;
  175. freq[val]++;
  176. };
  177. auto remove = [&](int pos) {
  178. int val = a[pos - 1];
  179. freq[val]--;
  180. if (freq[val] == 0) distinct--;
  181. };
  182.  
  183. for (const auto& qu : qs) {
  184. int L = qu.l, R = qu.r;
  185. while (curL > L) add(--curL);
  186. while (curR < R) add(++curR);
  187. while (curL < L) remove(curL++);
  188. while (curR > R) remove(curR--);
  189. ans[qu.idx] = distinct;
  190. }
  191. return ans;
  192. }
  193.  
  194. // ===================================================================
  195. // 6) Mo's Algorithm with Updates (Mo with modifications)
  196. // Maintains a time dimension. Use for queries with point updates.
  197. // Complexity: O((N + Q)^(5/3)).
  198. // Note: queries and updates are known offline. Each query must have
  199. // a 't' field = number of updates that happened before it.
  200. // This version uses a block size of N^(2/3).
  201. // ===================================================================
  202.  
  203. struct MoUpdateQuery {
  204. int l, r, t, idx;
  205. };
  206.  
  207. struct MoUpdate {
  208. int pos, oldVal, newVal;
  209. };
  210.  
  211. vector<int> moWithUpdates(vector<int> arr,
  212. const vector<MoUpdate>& updates,
  213. const vector<MoUpdateQuery>& queries) {
  214. int n = arr.size();
  215. int q = queries.size();
  216. int u = updates.size();
  217.  
  218. // Optimal block size for Mo with updates: N^(2/3)
  219. int block = max(1, (int)pow(n, 2.0/3.0));
  220.  
  221. vector<MoUpdateQuery> qs = queries; // copy to sort
  222. sort(qs.begin(), qs.end(), [&](const MoUpdateQuery& a, const MoUpdateQuery& b) {
  223. int blockA_l = a.l / block, blockB_l = b.l / block;
  224. if (blockA_l != blockB_l) return blockA_l < blockB_l;
  225. int blockA_r = a.r / block, blockB_r = b.r / block;
  226. if (blockA_r != blockB_r) return blockA_r < blockB_r;
  227. return a.t < b.t;
  228. });
  229.  
  230. vector<int> ans(q);
  231. // Coordinate compress values or use a large frequency array.
  232. // Here we assume values are up to 1e6; you can replace with unordered_map.
  233. vector<int> freq(1000005, 0);
  234. int curL = 0, curR = -1, curT = 0; // 0-indexed inclusive range
  235. int distinct = 0;
  236.  
  237. auto add = [&](int pos) {
  238. int val = arr[pos];
  239. if (freq[val] == 0) distinct++;
  240. freq[val]++;
  241. };
  242. auto remove = [&](int pos) {
  243. int val = arr[pos];
  244. freq[val]--;
  245. if (freq[val] == 0) distinct--;
  246. };
  247. auto applyUpdate = [&](int t, bool forward) {
  248. int pos = updates[t].pos;
  249. int oldVal = updates[t].oldVal;
  250. int newVal = updates[t].newVal;
  251. if (forward) {
  252. if (curL <= pos && pos <= curR) {
  253. remove(pos);
  254. arr[pos] = newVal;
  255. add(pos);
  256. } else {
  257. arr[pos] = newVal;
  258. }
  259. } else {
  260. if (curL <= pos && pos <= curR) {
  261. remove(pos);
  262. arr[pos] = oldVal;
  263. add(pos);
  264. } else {
  265. arr[pos] = oldVal;
  266. }
  267. }
  268. };
  269.  
  270. for (const auto& qu : qs) {
  271. while (curT < qu.t) applyUpdate(curT++, true);
  272. while (curT > qu.t) applyUpdate(--curT, false);
  273. while (curL > qu.l) add(--curL);
  274. while (curR < qu.r) add(++curR);
  275. while (curL < qu.l) remove(curL++);
  276. while (curR > qu.r) remove(curR--);
  277. ans[qu.idx] = distinct;
  278. }
  279. return ans;
  280. }
  281.  
  282. // ===================================================================
  283. // 7) Sweep Line: Count Points in Rectangles
  284. // Given N points (x,y) and Q queries each asking number of points
  285. // with x in [x1,x2] and y in [y1,y2].
  286. // Use offline sweep by x-coordinate, BIT over y.
  287. // Complexity: O((N+Q) log N)
  288. // ===================================================================
  289.  
  290. struct Point {
  291. int x, y;
  292. };
  293.  
  294. struct RectQuery {
  295. int x1, y1, x2, y2, idx, sign; // sign for inclusion-exclusion
  296. };
  297.  
  298. vector<int> countPointsInRectangles(const vector<Point>& pts,
  299. const vector<pair<pair<int,int>, pair<int,int>>>& rects) {
  300. int n = pts.size();
  301. int q = rects.size();
  302.  
  303. // compress y coordinates
  304. vector<int> ys;
  305. for (auto& p : pts) ys.push_back(p.y);
  306. for (auto& r : rects) {
  307. ys.push_back(r.first.second);
  308. ys.push_back(r.second.second);
  309. }
  310. sort(ys.begin(), ys.end());
  311. ys.erase(unique(ys.begin(), ys.end()), ys.end());
  312.  
  313. auto getY = [&](int y) {
  314. return int(lower_bound(ys.begin(), ys.end(), y) - ys.begin()) + 1;
  315. };
  316.  
  317. vector<RectQuery> events;
  318. for (int i = 0; i < q; ++i) {
  319. int x1 = rects[i].first.first, y1 = rects[i].first.second;
  320. int x2 = rects[i].second.first, y2 = rects[i].second.second;
  321. // add events: at x2 (inclusive) with +, at x1-1 with -
  322. events.push_back({x2, y1, y2, i, +1});
  323. if (x1 > 1) events.push_back({x1 - 1, y1, y2, i, -1});
  324. }
  325.  
  326. sort(events.begin(), events.end(), [](const RectQuery& a, const RectQuery& b) {
  327. return a.x1 < b.x1; // sort by x-coordinate (first field)
  328. });
  329.  
  330. vector<Point> sortedPts = pts;
  331. sort(sortedPts.begin(), sortedPts.end(), [](const Point& a, const Point& b) {
  332. return a.x < b.x;
  333. });
  334.  
  335. Fenwick bit(ys.size());
  336. vector<int> ans(q, 0);
  337. int p = 0;
  338. for (auto& ev : events) {
  339. int limitX = ev.x1;
  340. while (p < n && sortedPts[p].x <= limitX) {
  341. bit.add(getY(sortedPts[p].y), 1);
  342. p++;
  343. }
  344. int yl = getY(ev.y1);
  345. int yr = getY(ev.y2);
  346. int cnt = bit.rangeSum(yl, yr);
  347. ans[ev.idx] += ev.sign * cnt;
  348. }
  349. return ans;
  350. }
  351.  
  352. // ===================================================================
  353. // 8) Offline Dynamic Connectivity (DSU with rollback + Segment Tree over time)
  354. // Process edges added over time, answer connectivity queries.
  355. // Use Divide and Conquer on time (segment tree over time) + DSU rollback.
  356. // Complexity: O((N + M) log Q * α(N))
  357. // ===================================================================
  358.  
  359. struct DSU {
  360. vector<int> parent, sz;
  361. vector<pair<int,int>> history; // (child, parent_before_merge)
  362. int comps;
  363.  
  364. DSU(int n) : parent(n+1), sz(n+1, 1), comps(n) {
  365. iota(parent.begin(), parent.end(), 0);
  366. }
  367.  
  368. int find(int x) const {
  369. while (parent[x] != x) x = parent[x];
  370. return x;
  371. }
  372.  
  373. bool unite(int a, int b) {
  374. a = find(a); b = find(b);
  375. if (a == b) return false;
  376. if (sz[a] < sz[b]) swap(a, b);
  377. history.push_back({b, parent[b]});
  378. parent[b] = a;
  379. sz[a] += sz[b];
  380. comps--;
  381. return true;
  382. }
  383.  
  384. void rollback(int snap) {
  385. while ((int)history.size() > snap) {
  386. auto [b, oldParent] = history.back();
  387. history.pop_back();
  388. int a = parent[b];
  389. sz[a] -= sz[b];
  390. parent[b] = oldParent;
  391. comps++;
  392. }
  393. }
  394.  
  395. int snapshot() const { return (int)history.size(); }
  396. };
  397.  
  398. struct TimeEdge {
  399. int u, v, l, r; // active in [l, r]
  400. };
  401.  
  402. struct TimeQuery {
  403. int time, u, v; // query at time: are u and v connected?
  404. };
  405.  
  406. class SegmentTreeOverTime {
  407. int n; // number of time steps
  408. vector<vector<pair<int,int>>> tree; // each node stores edges (u,v)
  409.  
  410. void addEdge(int node, int l, int r, int ql, int qr, int u, int v) {
  411. if (ql <= l && r <= qr) {
  412. tree[node].push_back({u, v});
  413. return;
  414. }
  415. int mid = (l + r) / 2;
  416. if (ql <= mid) addEdge(node*2, l, mid, ql, qr, u, v);
  417. if (qr > mid) addEdge(node*2+1, mid+1, r, ql, qr, u, v);
  418. }
  419.  
  420. public:
  421. SegmentTreeOverTime(int n) : n(n), tree(4*n + 5) {}
  422.  
  423. void addEdge(int l, int r, int u, int v) {
  424. if (l > r) return;
  425. addEdge(1, 1, n, l, r, u, v);
  426. }
  427.  
  428. void dfs(int node, int l, int r, DSU& dsu, const vector<TimeQuery>& queries, vector<bool>& ans) {
  429. int snap = dsu.snapshot();
  430. for (auto &e : tree[node]) {
  431. dsu.unite(e.first, e.second);
  432. }
  433. if (l == r) {
  434. // answer queries at this time
  435. for (auto &q : queries) {
  436. if (q.time == l) {
  437. ans[q.u] = (dsu.find(q.u) == dsu.find(q.v)); // assuming q.u stores index
  438. }
  439. }
  440. } else {
  441. int mid = (l + r) / 2;
  442. dfs(node*2, l, mid, dsu, queries, ans);
  443. dfs(node*2+1, mid+1, r, dsu, queries, ans);
  444. }
  445. dsu.rollback(snap);
  446. }
  447. };
  448.  
  449. // ===================================================================
  450. // 9) Parallel Binary Search
  451. // When we have many queries and each can be answered by binary search
  452. // on a monotonic predicate, we can process all queries simultaneously.
  453. // Example: find k‑th smallest in range, or find minimal x such that ...
  454. // This is a skeleton; you need to implement the check() function.
  455. // ===================================================================
  456.  
  457. struct PBSQuery {
  458. int l, r, k, idx; // example: query about k-th smallest in range [l,r]
  459. int low, high; // answer range
  460. };
  461.  
  462. // Placeholder for the check function.
  463. // It should return true if the answer for this query is <= mid.
  464. bool check(int mid, const PBSQuery& q) {
  465. // This depends on the problem.
  466. // You can preprocess data as mid increases.
  467. return true;
  468. }
  469.  
  470. vector<int> parallelBinarySearch(int n, const vector<PBSQuery>& queries) {
  471. int q = queries.size();
  472. vector<int> lo(q), hi(q), ans(q);
  473. for (int i = 0; i < q; ++i) {
  474. lo[i] = queries[i].low;
  475. hi[i] = queries[i].high;
  476. }
  477. bool changed = true;
  478. while (changed) {
  479. changed = false;
  480. vector<vector<int>> bucket(n + 2); // max answer range
  481. for (int i = 0; i < q; ++i) {
  482. if (lo[i] < hi[i]) {
  483. int mid = (lo[i] + hi[i]) / 2;
  484. bucket[mid].push_back(i);
  485. changed = true;
  486. }
  487. }
  488. if (!changed) break;
  489.  
  490. // Sweep over mid and apply updates to a data structure.
  491. // For each mid, we have a list of query indices.
  492. // We need to evaluate check(mid, query) for each query.
  493. // For example, if we need to answer "how many elements <= mid in range",
  494. // we can maintain a Fenwick tree of positions as we increment mid.
  495. // Here we just call the check function (which you must implement).
  496. for (int mid = 0; mid <= n; ++mid) {
  497. // apply changes to reach value 'mid'
  498. // ...
  499. for (int idx : bucket[mid]) {
  500. if (check(mid, queries[idx])) {
  501. hi[idx] = mid;
  502. } else {
  503. lo[idx] = mid + 1;
  504. }
  505. }
  506. }
  507. }
  508. for (int i = 0; i < q; ++i) ans[i] = lo[i];
  509. return ans;
  510. }
  511.  
  512. // ===================================================================
  513. // 10) CDQ Divide and Conquer (Example: 2D Partial Order)
  514. // Solves problems where we need to count points (x, y) that satisfy
  515. // x <= q.x and y <= q.y. Complexity O(N log N) for 2D.
  516. // This is a skeleton; the merge logic depends on the specific problem.
  517. // ===================================================================
  518.  
  519. struct CDQPoint {
  520. int x, y, type, idx; // type: 0 for point, 1 for query (with sign)
  521. };
  522.  
  523. // The function cdq(items, l, r) will be implemented with merge logic.
  524. // The merge part typically uses BIT to count points from the left half
  525. // that satisfy conditions for queries in the right half.
  526. void cdq(vector<CDQPoint>& items, int l, int r) {
  527. if (l >= r) return;
  528. int mid = (l + r) / 2;
  529. cdq(items, l, mid);
  530. cdq(items, mid + 1, r);
  531.  
  532. // Merge step: count contributions from left half (type 0) to right half (type 1)
  533. // using a Fenwick tree over y-coordinates.
  534. // ...
  535. // Then merge the two halves back sorted by x.
  536. }
  537.  
  538. // ===================================================================
  539. // 11) Euler Tour + Offline Subtree Sum Queries
  540. // Flattens a tree into an array using Euler Tour, then answers subtree
  541. // sum queries offline with prefix sums or BIT.
  542. // Complexity: O(N + Q) after DFS.
  543. // ===================================================================
  544.  
  545. vector<int> adj[100005];
  546. int timer = 0;
  547. int tin[100005], tout[100005];
  548. int flat[100005]; // array representation of the tree (holds node id or value)
  549.  
  550. void dfs(int node, int parent) {
  551. tin[node] = ++timer;
  552. flat[timer] = node; // or value[node]
  553. for (int child : adj[node]) {
  554. if (child != parent) dfs(child, node);
  555. }
  556. tout[node] = timer;
  557. }
  558.  
  559. // After DFS, a subtree query for node u becomes a range sum query on [tin[u], tout[u]]
  560. // in the array 'flat'. You can answer it with prefix sums or BIT.
  561.  
  562. // ===================================================================
  563. // 12) Two Pointers: Count Pairs with Sum <= K
  564. // Given two arrays, count pairs (i,j) such that a[i] + b[j] <= K.
  565. // Complexity O(N log N + M log M).
  566. // ===================================================================
  567.  
  568. ll countPairsSumLE(vector<int>& a, vector<int>& b, ll K) {
  569. sort(a.begin(), a.end());
  570. sort(b.begin(), b.end());
  571. ll ans = 0;
  572. int j = (int)b.size() - 1;
  573. for (int i = 0; i < (int)a.size(); ++i) {
  574. while (j >= 0 && a[i] + b[j] > K) --j;
  575. if (j < 0) break;
  576. ans += (j + 1);
  577. }
  578. return ans;
  579. }
  580.  
  581. // ===================================================================
  582. // main() – example usage (you can extend or modify)
  583. // ===================================================================
  584.  
  585. int main() {
  586. ios::sync_with_stdio(false);
  587. cin.tie(nullptr);
  588.  
  589. // Example: distinct elements in range
  590. vector<int> arr = {1, 2, 1, 3, 2, 4};
  591. vector<pair<int,int>> queries = {{1,3}, {2,5}, {3,6}};
  592. auto res = countDistinctInRange(arr, queries);
  593. cout << "Distinct in ranges: ";
  594. for (int x : res) cout << x << " ";
  595. cout << "\n";
  596.  
  597. // Example: count subarrays with sum in [L,R]
  598. vector<int> nums = {1, -2, 3, 4, -1, 2};
  599. ll L = 1, R = 5;
  600. cout << "Number of subarrays with sum in [1,5]: " << countSubarraysSumInRange(nums, L, R) << "\n";
  601.  
  602. // Example: Mo's algorithm distinct
  603. auto moRes = moDistinct(arr, queries);
  604. cout << "Mo distinct: ";
  605. for (int x : moRes) cout << x << " ";
  606. cout << "\n";
  607.  
  608. return 0;
  609. }
Success #stdin #stdout 0.01s 5904KB
stdin
Standard input is empty
stdout
Distinct in ranges: 2 3 4 
Number of subarrays with sum in [1,5]: 12
Mo distinct: 2 3 4