import java.util.*;
import java.io.*;
// Java program for the above approach
public class GFG{
public static int M = 100000;
// Stores the Segment tree
public static ArrayList<ArrayList<Integer>> tree =
new ArrayList<ArrayList<Integer>>();
// Function to update Segment tree, the root
// of which contains the length of the LIS
public static void update_tree(int start, int end,
int update_idx, int length_t,
int count_c, int idx)
{
// If the intervals
// are overlapping completely
if (start == end && start == update_idx) {
tree.get(idx).set(0, Math.max(tree.get(idx).get(0), length_t));
tree.get(idx).set(1, count_c);
return;
}
// If intervals are not overlapping
if (update_idx < start || end < update_idx) {
return;
}
// If intervals are partially overlapping
int mid = (start + end) / 2;
update_tree(start, mid, update_idx,
length_t, count_c, 2 * idx);
update_tree(mid + 1, end, update_idx,
length_t, count_c, 2 * idx + 1);
// If length_t of left and
// right child are equal
if (tree.get(2 * idx).get(0) == tree.get(2 * idx + 1).get(0)) {
tree.set(idx, new ArrayList<Integer>(
List.of(tree.get(2 * idx).get(0),
tree.get(2 * idx).get(1) +
tree.get(2 * idx + 1).get(1))
));
}
// If length_t of left > length_t right child
else if (tree.get(2 * idx).get(0) > tree.get(2 * idx + 1).get(0)) {
tree.set(idx, new ArrayList<Integer>(
List.of(tree.get(2 * idx).get(0), tree.get(2 * idx).get(1))
));
}
// If length_t of left < length_t right child
else {
tree.set(idx, new ArrayList<Integer>(
List.of(tree.get(2 * idx + 1).get(0), tree.get(2 * idx + 1).get(1))
));
}
}
// Function to find the LIS length
// and count in the given range
public static ArrayList<Integer> query(int start, int end,
int query_start,
int query_end, int idx)
{
// If the intervals
// are overlapping completely
if (query_start <= start && end <= query_end) {
return new ArrayList<Integer>(tree.get(idx));
}
// If intervals are not overlapping
ArrayList<Integer> temp = new ArrayList<Integer>(
List.of(Integer.MIN_VALUE, 0 )
);
if (end < query_start || query_end < start) {
return new ArrayList<Integer>(temp);
}
// If intervals are partially overlapping
int mid = (start + end) / 2;
ArrayList<Integer> left_child = query(start, mid,
query_start,
query_end, 2 * idx);
ArrayList<Integer> right_child = query(mid + 1, end,
query_start,
query_end, 2 * idx + 1);
// If length_t of left child is greater
// than length_t of right child
if (left_child.get(0) > right_child.get(0)) {
return new ArrayList<Integer>(left_child);
}
// If length_t of right child is
// greater than length_t of left child
if (right_child.get(0) > left_child.get(0)) {
return new ArrayList<Integer>(right_child);
}
// If length_t of left
// and right child are equal
// return there sum
return new ArrayList<Integer>(
List.of(
left_child.get(0),
left_child.get(1) + right_child.get(1)
)
);
}
// Function to find count
// of LIS in the given array
public static int countLIS(int arr[], int n)
{
// Generating value-index pair array
ArrayList<ArrayList<Integer>> pair_array = new ArrayList<ArrayList<Integer>>();
for(int i = 0 ; i < n ; i++){
pair_array.add(new ArrayList<Integer>(
List.of(arr[i], i)
));
}
// Sort array of pairs with increasing order
// of value and decreasing order of index
Collections.sort(pair_array, new comp());
// Traverse the array
// and perform query updates
for (int i = 0 ; i < n ; i++) {
int update_idx = pair_array.get(i).get(1);
// If update index is the 1st index
if (update_idx == 0) {
update_tree(0, n - 1, 0, 1, 1, 1);
continue;
}
// Query over the interval [0, update_idx -1]
ArrayList<Integer> temp = query(0, n - 1, 0,
update_idx - 1, 1);
// Update the segment tree
update_tree(0, n - 1, update_idx, temp.get(0) + 1,
Math.max(1, temp.get(1)), 1);
}
// Stores the final answer
ArrayList<Integer> ans = query(0, n - 1, 0, n - 1, 1);
// Return answer
return ans.get(1);
}
// Driver code
public static void main(String args[])
{
int arr[] = { 1, 3, 5, 4, 7 };
int n = arr.length;
for(int i = 0 ; i < 4*M + 1 ; i++){
tree.add(new ArrayList<Integer>(
List.of(Integer.MIN_VALUE,0)
));
}
System.out.println(countLIS(arr, n));
}
}
// Comparator function to sort an array of pairs
// in increasing order of their 1st element and
// thereafter in decreasing order of the 2nd
public class comp implements Comparator<ArrayList<Integer>>{
public int compare(ArrayList<Integer> a, ArrayList<Integer> b)
{
if (a.get(0).equals(b.get(0))) {
return b.get(1).compareTo(a.get(1));
}
return a.get(0).compareTo(b.get(0));
}
}
// This code is contributed by subhamgoyal2014.