#include <bits/stdc++.h>
using namespace std;
// =====================================================================================
// This file contains a collection of functions and a data structure for
// MERGE SORT TREE.
//
// A Merge Sort Tree is a Segment Tree where each node stores a SORTED VECTOR
// of the elements in its segment. It is used to answer range queries that ask
// about order statistics (e.g., count of elements ≤ X) in a subarray [L, R].
//
// All functions are documented with:
// - What they solve
// - Input parameters
// - Return value
// - Time complexity
// - Constraints / assumptions
// - Important notes
//
// You can use these functions as black boxes. Read the comments carefully
// to understand what each one does and when to use it.
// =====================================================================================
// =====================================================================================
// 1) MERGE SORT TREE CLASS
// A class that builds a merge sort tree from a vector and provides query methods.
// =====================================================================================
class MergeSortTree {
private:
int n; // size of the original array
vector<vector<int>> tree; // tree[node] = sorted vector of that segment
// Build the tree recursively from the array a.
// Parameters:
// - node: current tree node index (1‑based)
// - l, r: segment boundaries [l, r] (0‑based inclusive)
// - a: original array
void build(int node, int l, int r, const vector<int>& a) {
if (l == r) {
tree[node].push_back(a[l]);
return;
}
int mid = (l + r) / 2;
build(node * 2, l, mid, a);
build(node * 2 + 1, mid + 1, r, a);
// Merge the two sorted vectors from children
merge(tree[node * 2].begin(), tree[node * 2].end(),
tree[node * 2 + 1].begin(), tree[node * 2 + 1].end(),
back_inserter(tree[node]));
}
// Internal query: count elements ≤ X in range [ql, qr].
int queryLessEqual(int node, int l, int r, int ql, int qr, int X) const {
if (qr < l || r < ql) return 0; // no overlap
if (ql <= l && r <= qr) { // full cover
return upper_bound(tree[node].begin(), tree[node].end(), X) - tree[node].begin();
}
int mid = (l + r) / 2;
return queryLessEqual(node * 2, l, mid, ql, qr, X) +
queryLessEqual(node * 2 + 1, mid + 1, r, ql, qr, X);
}
public:
// Constructor: builds the tree from array 'a'.
// Parameters:
// - a: vector of integers (can be negative, zero, positive).
// Time complexity: O(n log n), where n = a.size().
// Memory: O(n log n) because each element appears in log n nodes.
MergeSortTree(const vector<int>& a) {
n = a.size();
tree.resize(4 * n + 5);
if (n > 0) build(1, 0, n - 1, a);
}
// 1.1) Query: count of elements in range [L, R] that are <= X.
// Parameters:
// - L, R: inclusive indices of the subarray (0‑based).
// - X: the upper bound value.
// Returns:
// - number of elements a[i] such that L <= i <= R and a[i] <= X.
// Time complexity: O(log² n) (visits O(log n) nodes, each does a binary search).
// Constraint: L <= R, 0 <= L,R < n.
// Note: if X is very small, result may be 0; if X is very large, result = length.
int queryLessEqual(int L, int R, int X) const {
if (L > R || n == 0) return 0;
return queryLessEqual(1, 0, n - 1, L, R, X);
}
// 1.2) Query: count of elements in range [L, R] that are > X.
// Parameters:
// - L, R: inclusive indices.
// - X: the threshold value.
// Returns:
// - number of elements > X in the subarray.
// Time complexity: O(log² n).
// Note: uses queryLessEqual to compute: total length - count(<= X).
int queryGreater(int L, int R, int X) const {
if (L > R || n == 0) return 0;
int len = R - L + 1;
return len - queryLessEqual(L, R, X);
}
// 1.3) Query: count of elements in range [L, R] that are between LOW and HIGH
// (inclusive, i.e., LOW <= a[i] <= HIGH).
// Parameters:
// - L, R: inclusive indices.
// - LOW, HIGH: the lower and upper bounds (LOW <= HIGH).
// Returns:
// - number of elements in [L,R] with value in [LOW, HIGH].
// Time complexity: O(log² n).
// Note: uses queryLessEqual twice: count(<= HIGH) - count(< LOW) =>
// count(<= HIGH) - count(<= LOW-1).
int queryInRange(int L, int R, int LOW, int HIGH) const {
if (L > R || LOW > HIGH || n == 0) return 0;
return queryLessEqual(L, R, HIGH) - queryLessEqual(L, R, LOW - 1);
}
// 1.4) Query: find the k‑th smallest element (1‑based) in the subarray [L, R].
// Parameters:
// - L, R: inclusive indices.
// - k: 1‑based order (1 = smallest, length = largest).
// Returns:
// - the value of the k‑th smallest element in the subarray.
// - If k is out of range, the behaviour is undefined (you must ensure 1 <= k <= len).
// Time complexity: O(log³ n) typically (binary search over value range,
// each check O(log² n)). For a value range of size up to 2e9, ~31 * log² n.
// Constraint: the elements must be comparable (integers). The array values
// must fit in int. The binary search assumes values are between -1e9 and 1e9.
// If your values can be outside this range, adjust LOW and HIGH accordingly.
// Note: This implementation uses binary search on the value domain.
int queryKthSmallest(int L, int R, int k) const {
if (L > R || n == 0) return 0;
int len = R - L + 1;
if (k < 1 || k > len) return 0; // optional safety
// Adjust these bounds if your values can be outside [-1e9, 1e9]
int low = -1000000000, high = 1000000000;
while (low < high) {
int mid = low + (high - low) / 2;
int cnt = queryLessEqual(L, R, mid);
if (cnt >= k)
high = mid;
else
low = mid + 1;
}
return low;
}
// 1.5) Query: find the k‑th smallest using coordinate compression (if values are known).
// This version assumes that all possible values are integers and we can compress them.
// It is faster if we have a sorted list of all unique values.
// Parameters:
// - L, R: inclusive indices.
// - k: 1‑based order.
// - sortedVals: a sorted vector of all unique values that may appear.
// Returns:
// - the k‑th smallest value.
// Time complexity: O(log² n * log m) where m = sortedVals.size().
// Constraint: sortedVals must contain all values from the array.
int queryKthSmallestCompressed(int L, int R, int k, const vector<int>& sortedVals) const {
if (L > R || n == 0) return 0;
int len = R - L + 1;
if (k < 1 || k > len) return 0;
int low = 0, high = (int)sortedVals.size() - 1;
while (low < high) {
int mid = (low + high) / 2;
int cnt = queryLessEqual(L, R, sortedVals[mid]);
if (cnt >= k)
high = mid;
else
low = mid + 1;
}
return sortedVals[low];
}
// 1.6) Query: count of pairs (i,j) with L <= i < j <= R and a[i] + a[j] <= K.
// This is a common trick used in ECPC/ACPC problems.
// Parameters:
// - L, R: inclusive range of indices.
// - K: the sum limit.
// Returns:
// - number of pairs (i,j) within [L,R] with i<j and a[i]+a[j] <= K.
// Time complexity: O(log² n) * (??) Actually this is not directly supported
// by a simple merge sort tree. The correct way is to use a fenwick tree
// of order statistics or a merge sort tree with two pointers on the fly.
// However, we can implement a function that for each element counts
// how many previous elements in the range satisfy the condition using
// repeated queries. That would be O(len * log² n), which is too slow.
// Instead, we will NOT include this as a black box function because it
// is not efficient. Instead, we provide a note.
// Note: For range pair counting, use a different approach (e.g., Mo's algorithm,
// or Fenwick tree offline). Merge sort tree is not ideal for this.
// This function is intentionally omitted.
};
// =====================================================================================
// 2) HELPER FUNCTIONS (not class methods) for common tasks using Merge Sort Tree
// =====================================================================================
// 2.1) Count inversions in an array using merge sort (O(n log n)).
// This is not a merge sort tree, but a classic divide-and-conquer.
// Included here because it is often used in similar problems.
// Parameters:
// - a: vector of integers (will be modified during the process).
// Returns:
// - the number of inversions (i < j and a[i] > a[j]).
// Time complexity: O(n log n).
// Constraint: none, works for any integers.
// Note: This function modifies the input (sorts it). If you need the original,
// pass a copy.
long long countInversionsMergeSort(vector<int>& a) {
int n = a.size();
if (n <= 1) return 0;
int mid = n / 2;
vector<int> left(a.begin(), a.begin() + mid);
vector<int> right(a.begin() + mid, a.end());
long long inv = countInversionsMergeSort(left) + countInversionsMergeSort(right);
int i = 0, j = 0, k = 0;
while (i < (int)left.size() && j < (int)right.size()) {
if (left[i] <= right[j]) {
a[k++] = left[i++];
} else {
a[k++] = right[j++];
inv += (int)left.size() - i;
}
}
while (i < (int)left.size()) a[k++] = left[i++];
while (j < (int)right.size()) a[k++] = right[j++];
return inv;
}
// 2.2) Count the number of subarrays in [L, R] with sum <= K using prefix sums + Merge Sort Tree.
// This is an advanced trick: for an array (can contain negatives?), we need a
// different approach. But if all elements are non-negative, we can use sliding window.
// For general values, we can compute prefix sums P[0..n], then count pairs (i,j)
// with L <= i < j <= R and P[j] - P[i] <= K => P[j] <= P[i] + K.
// This can be answered by a Merge Sort Tree built on prefix sums, but we need
// to ensure index order. Actually we can iterate over j and query how many previous
// prefix sums are >= P[j] - K using a Fenwick tree over compressed prefix sums.
// So we provide a function that uses a Fenwick tree offline, not a merge sort tree.
// For the purpose of this template, we will mention it but not implement it,
// because it is not a pure merge sort tree application.
// =====================================================================================
// 3) ADVANCED / TRICKS THAT APPEARED IN ECPC/ACPC CONTESTS
// =====================================================================================
// (ASSUMPTION) The class MergeSortTree is already defined as in the previous template.
// It provides:
// - queryLessEqual(L, R, X) -> count of elements <= X in [L,R]
// - queryInRange(L, R, LOW, HIGH) -> count of elements in [LOW, HIGH] in [L,R]
// - queryKthSmallest(L, R, k) -> k-th smallest (1-indexed) in [L,R]
// =====================================================================================
// 3.1) PROBLEM: Count how many elements in subarray [L, R] are ≤ X.
// Parameters:
// - mst: a MergeSortTree object built from the original array.
// - L, R: inclusive 0-based indices of the subarray.
// - X: the upper bound value (inclusive).
// Returns:
// - the number of elements a[i] with L ≤ i ≤ R and a[i] ≤ X.
// Time complexity: O(log² N) (calls the tree's query method).
// Constraint: L ≤ R and 0 ≤ L,R < array size.
// Note: If X is very small, result may be 0.
// =====================================================================================
int countElementsLE(const MergeSortTree& mst, int L, int R, int X) {
return mst.queryLessEqual(L, R, X);
}
// =====================================================================================
// 3.2) PROBLEM: Find the median of the subarray [L, R].
// Parameters:
// - mst: a MergeSortTree object.
// - L, R: inclusive 0-based indices.
// Returns:
// - the median value. For odd length, it is the middle element.
// For even length, it returns the upper median (the (len/2 + 1)-th smallest).
// Time complexity: O(log³ N) (binary search inside the tree).
// Constraint: L ≤ R and array is not empty.
// Note: Median is defined as the element at position (len + 1) / 2
// (1-indexed) which gives the upper median for even lengths.
// =====================================================================================
int subarrayMedian(const MergeSortTree& mst, int L, int R) {
int len = R - L + 1;
int k = (len + 1) / 2; // 1-indexed position of the median
return mst.queryKthSmallest(L, R, k);
}
// =====================================================================================
// 3.3) PROBLEM: Count the number of contiguous subarrays whose sum is in the range [A, B].
// Parameters:
// - nums: vector of integers.
// - A: lower bound of the sum (inclusive).
// - B: upper bound of the sum (inclusive).
// Returns:
// - total count of subarrays with sum between A and B.
// Time complexity: O(N) where N = nums.size().
// CONSTRAINT: This function works ONLY if all elements in 'nums' are
// NON-NEGATIVE. If negative numbers are present, the answer
// will be WRONG because the sliding window technique relies
// on the monotonicity of sums when extending the window.
// Note: Uses the trick: count(≤ B) - count(≤ A-1).
// The helper 'countSubarraysAtMost' uses two pointers.
// =====================================================================================
long long countSubarraysAtMost(const vector<int>& nums, int target) {
if (target < 0) return 0; // sums are non-negative, so none can be ≤ negative
int n = nums.size();
long long ans = 0;
int l = 0;
long long sum = 0;
for (int r = 0; r < n; r++) {
sum += nums[r];
while (sum > target) {
sum -= nums[l++];
}
ans += (r - l + 1); // all subarrays ending at 'r' with start ≥ l are valid
}
return ans;
}
long long countSubarraysSumInRange(const vector<int>& nums, int A, int B) {
if (A > B) return 0;
// count(≤ B) - count(≤ A-1)
return countSubarraysAtMost(nums, B) - countSubarraysAtMost(nums, A - 1);
}
// =====================================================================================
// 3.4) PROBLEM: Count the number of pairs (i, j) with i < j and |a[i] - a[j]| ≤ K
// over the WHOLE array.
// Parameters:
// - nums: vector of integers (will be modified/sorted internally).
// - K: the maximum allowed absolute difference.
// Returns:
// - total number of valid pairs.
// Time complexity: O(N log N) due to sorting, then O(N) two-pointer scan.
// Constraint: none; works for positive and negative numbers.
// Note: This is for the entire array. For range queries [L,R], a more
// complex offline approach (e.g., Mo's algorithm with a Fenwick tree)
// is required, which is NOT included in this template.
// =====================================================================================
long long countPairsDiffAtMostK(vector<int>& nums, int K) {
sort(nums.begin(), nums.end());
int n = nums.size();
long long ans = 0;
int r = 0;
for (int l = 0; l < n; l++) {
if (r < l) r = l;
while (r + 1 < n && nums[r + 1] - nums[l] <= K) {
r++;
}
ans += (r - l); // pairs (l, l+1) ... (l, r)
}
return ans;
}
// =====================================================================================
// 3.5) PROBLEM: Count the number of elements in [L, R] that are between LOW and HIGH
// (inclusive, i.e., LOW ≤ a[i] ≤ HIGH).
// Parameters:
// - mst: a MergeSortTree object.
// - L, R: inclusive 0-based indices.
// - LOW, HIGH: inclusive lower and upper bounds.
// Returns:
// - count of elements in the subarray with value in [LOW, HIGH].
// Time complexity: O(log² N).
// Constraint: LOW ≤ HIGH.
// Note: This is essentially a wrapper for 'queryInRange'.
// =====================================================================================
int countElementsInRange(const MergeSortTree& mst, int L, int R, int LOW, int HIGH) {
return mst.queryInRange(L, R, LOW, HIGH);
}
// =====================================================================================
// 3.6) PROBLEM: Find the K-th smallest element in the subarray [L, R].
// Parameters:
// - mst: a MergeSortTree object.
// - L, R: inclusive 0-based indices.
// - K: the order (1-indexed). For example, K=1 returns the minimum,
// K=length returns the maximum.
// Returns:
// - the value of the K-th smallest element.
// Time complexity: O(log³ N).
// Constraint: 1 ≤ K ≤ (R - L + 1).
// Note: This is a direct wrapper for 'queryKthSmallest'.
// =====================================================================================
int kthSmallestInSubarray(const MergeSortTree& mst, int L, int R, int K) {
return mst.queryKthSmallest(L, R, K);
}
// =====================================================================================
// 3.7) PROBLEM: Count the number of elements in subarray [L, R] that are STRICTLY
// less than X (i.e., a[i] < X).
// Parameters:
// - mst: a MergeSortTree object.
// - L, R: inclusive 0-based indices.
// - X: the threshold (exclusive).
// Returns:
// - count of elements < X in the subarray.
// Time complexity: O(log² N).
// Note: Since queryLessEqual counts elements ≤ X, we simply pass X-1.
// For floating point values, this trick doesn't work; but this template
// assumes integer values.
// =====================================================================================
int countStrictlyLess(const MergeSortTree& mst, int L, int R, int X) {
return mst.queryLessEqual(L, R, X - 1);
}
// =====================================================================================
// 3.8) PROBLEM: Update a position (point update) in the array and still be able
// to answer merge-sort-tree style queries (like count ≤ X).
//
// ------- IMPORTANT WARNING -------
// The classic Merge Sort Tree (as defined in the previous template) does NOT
// support efficient point updates. If you change one element, you would have
// to rebuild the sorted vectors for all nodes on the path from the leaf to
// the root. Rebuilding one node costs O(size of the node). In the worst case,
// a single point update costs O(N log N), which is too slow for most problems.
//
// If your problem requires updates, use one of these alternatives:
// 1) Fenwick Tree of Fenwick Trees (Fenwick Tree of Order Statistics):
// - Supports point updates and range queries in O(log² N).
// - Requires coordinate compression of all values (offline).
// 2) Segment Tree of Balanced BSTs (e.g., std::multiset):
// - Update: O(log² N), Query: O(log² N).
// - Heavier constant factor.
// 3) Sqrt Decomposition (Block decomposition):
// - Simpler to implement, O(sqrt(N) * log(sqrt(N))) per query/update.
//
// The following function is a STUB to remind you that it is not supported.
// If you call it, it will do nothing or return an error (assert false).
// =====================================================================================
void pointUpdate(MergeSortTree& mst, int pos, int newVal) {
// This function intentionally does nothing.
// The classic Merge Sort Tree does not support efficient point updates.
// Rebuilding the whole tree or even a single node is O(N log N) in the
// worst case, which defeats the purpose.
// Please use a Fenwick tree of order statistics or a different data structure.
// Uncomment the line below to cause a runtime error if accidentally called.
// assert(false && "Point updates are not supported by the classic Merge Sort Tree.");
// If you absolutely must use this with rebuild, here is the inefficient way:
// (DO NOT USE in contests unless N and Q are very small).
// 1. Update the original array.
// 2. Rebuild the entire tree: mst = MergeSortTree(updatedArray); // O(N log N)
}
// =====================================================================================
// 4) TEMPLATE FOR USING MERGE SORT TREE IN A COMPETITIVE PROGRAMMING SETTING
// (Example main function – you can ignore or adapt)
// =====================================================================================
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Example 1: Build a merge sort tree from an array.
vector<int> arr = {5, 2, 8, 1, 9, 3, 7, 4, 6};
MergeSortTree mst(arr);
// Query: count elements <= 5 in subarray [2, 6] (0‑based)
int L = 2, R = 6, X = 5;
cout << "Number <= 5 in [2,6]: " << mst.queryLessEqual(L, R, X) << '\n'; // Expected: 3 (elements 1,3,4)
// Query: count elements in [3, 7] in subarray [1,5]
cout << "Elements in [3,7] in [1,5]: " << mst.queryInRange(1, 5, 3, 7) << '\n';
// Query: 3rd smallest in whole array
cout << "3rd smallest in whole array: " << mst.queryKthSmallest(0, 8, 3) << '\n';
// Example 2: Compressed kth smallest
vector<int> vals = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // all unique values
cout << "3rd smallest (compressed): " << mst.queryKthSmallestCompressed(0, 8, 3, vals) << '\n';
return 0;
}
// =====================================================================================
// 5) GLOSSARY OF TERMS USED
// =====================================================================================
//
// - Merge Sort Tree: A segment tree where each node stores a sorted list of the elements
// in its segment. It is built by merging the sorted lists of children (like merge sort).
// - Node: a node in the segment tree, representing a contiguous segment of the array.
// - Segment: a contiguous subarray of the original array.
// - Order statistic: a value that describes the position of an element when the data is sorted
// (e.g., the smallest, the 10th smallest).
// - K‑th smallest: the element that would be at position k if the subarray were sorted
// in ascending order (1‑based).
// - Binary search: a method to find a target value in a sorted array by repeatedly halving
// the search space. Here used to find the k‑th smallest.
// - Logarithmic: O(log n) time complexity, meaning the time grows slowly as n increases.
// - Coordinate compression: mapping each distinct value to a smaller integer (its rank)
// to use in data structures like Fenwick trees; here used to speed up kth smallest.
// - Fenwick tree (BIT): a different data structure for prefix sums and order statistics;
// not part of this template, but mentioned for context.
// - Mo's algorithm: an offline algorithm for range queries, not used here.
// - Inversion: a pair (i, j) such that i < j and a[i] > a[j].
// =====================================================================================