/*package whatever //do not write package name here */
import java.io.*;
import java.util.*;
class GFG {
static final int MAX = 1000;
// Constructs a segment tree and stores tree[]
static void buildTree(int treeIndex, int l, int r,
List<Pair<Integer, Integer> > a,
List<List<Integer> > tree)
{
/* l => start of range,
r => ending of a range
treeIndex => index in the Segment Tree/Merge
Sort Tree */
/* leaf node */
if (l == r) {
tree.get(treeIndex).add(a.get(l).second);
return;
}
int mid = (l + r) / 2;
/* building left subtree */
buildTree(2 * treeIndex, l, mid, a, tree);
/* building right subtree */
buildTree(2 * treeIndex + 1, mid + 1, r, a, tree);
/* merging left and right child in sorted order */
List<Integer> leftChild = tree.get(2 * treeIndex);
List<Integer> rightChild
= tree.get(2 * treeIndex + 1);
List<Integer> currentTree = new ArrayList<>();
int leftIndex = 0, rightIndex = 0;
while (leftIndex < leftChild.size()
&& rightIndex < rightChild.size()) {
if (leftChild.get(leftIndex)
< rightChild.get(rightIndex)) {
currentTree.add(leftChild.get(leftIndex));
leftIndex++;
}
else {
currentTree.add(rightChild.get(rightIndex));
rightIndex++;
}
}
while (leftIndex < leftChild.size()) {
currentTree.add(leftChild.get(leftIndex));
leftIndex++;
}
while (rightIndex < rightChild.size()) {
currentTree.add(rightChild.get(rightIndex));
rightIndex++;
}
tree.set(treeIndex, currentTree);
}
// Returns the Kth smallest number in query range
static int queryRec(int segmentStart, int segmentEnd,
int queryStart, int queryEnd,
int treeIndex, int K,
List<List<Integer> > tree)
{
/*
segmentStart => start of a Segment,
segmentEnd => ending of a Segment,
queryStart => start of a query range,
queryEnd => ending of a query range,
treeIndex => index in the Segment
Tree/Merge Sort Tree,
K => kth smallest number to find */
if (segmentStart == segmentEnd)
return tree.get(treeIndex).get(0);
int mid = (segmentStart + segmentEnd) / 2;
// finds the last index in the segment
// which is <= queryEnd
List<Integer> leftChild = tree.get(2 * treeIndex);
int last_in_query_range
= upperBound(leftChild, queryEnd);
// finds the first index in the segment
// which is >= queryStart
int first_in_query_range
= lowerBound(leftChild, queryStart);
int M = last_in_query_range - first_in_query_range;
if (M >= K) {
// Kth smallest is in left subtree,
// so recursively call left subtree for Kth
// smallest number
return queryRec(segmentStart, mid, queryStart,
queryEnd, 2 * treeIndex, K,
tree);
}
else {
// Kth smallest is in right subtree,
// so recursively call right subtree for the
// (K-M)th smallest number
return queryRec(mid + 1, segmentEnd, queryStart,
queryEnd, 2 * treeIndex + 1,
K - M, tree);
}
}
static int query(int queryStart, int queryEnd, int K,
int n, List<Pair<Integer, Integer> > a,
List<Integer>[] tree)
{
return queryRec(0, n - 1, queryStart - 1,
queryEnd - 1, 1, K, tree);
}
public static void main(String[] args)
{
int[] arr = { 3, 2, 5, 1, 8, 9 };
int n = arr.length;
// vector of pairs of form {element, index}
List<Pair<Integer, Integer> > v
= new ArrayList<Pair<Integer, Integer> >();
for (int i = 0; i < n; i++) {
v.add(new Pair<Integer, Integer>(arr[i], i));
}
// sort the vector
Collections.sort(
v, new Comparator<Pair<Integer, Integer> >() {
public int compare(Pair<Integer, Integer> a,
Pair<Integer, Integer> b)
{
return a.getKey().compareTo(b.getKey());
}
});
// Construct segment tree in tree[]
List<Integer>[] tree = new List[n * 4];
for (int i = 0; i < n * 4; i++) {
tree[i] = new ArrayList<Integer>();
}
buildTree(1, 0, n - 1, v, tree);
// Answer queries
// kSmallestIndex hold the index of the kth smallest
// number
int kSmallestIndex = query(2, 5, 2, n, v, tree);
System.out.println(arr[kSmallestIndex]);
kSmallestIndex = query(1, 6, 4, n, v, tree);
System.out.println(arr[kSmallestIndex]);
}
}