Skip to content
Related Articles

Related Articles

Improve Article
Save Article
Like Article

Length of Longest Increasing Subsequences (LIS) using Segment Tree

  • Difficulty Level : Hard
  • Last Updated : 26 Nov, 2021

Given an array arr[] of size N, the task is to count the number of longest increasing subsequences present in the given array.

Example:

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.

Input: arr[] = {2, 2, 2, 2, 2}
Output: 5
Explanation: The length of the longest increasing subsequence is 1, i.e. {2}. Therefore, count of longest increasing subsequences of length 1 is 5. 
 



Input: arr[] = {1, 3, 5, 4, 7}
Output: 2
Explanation: The length of the longest increasing subsequence is 4, and there are 2 longest increasing subsequences of length 4, i.e. {1, 3, 4, 7} and {1, 3, 5, 7}.

Approach: An approach to the given problem has been already discussed using dynamic programming in this article. 
This article suggests a different approach using segment trees. Follow the below steps to solve the given problem:

  • Initialise the segment tree as an array of pairs initially containing pairs of (0, 0), where the 1st element represents the length of LIS and 2nd element represents the count of LIS of current length.
  • The 1st element of the segment tree can be calculated similarly to the approach discussed in this article.
  • The 2nd element of the segment tree can be calculated using the following steps:
    • If cases where the length of left child > length of right child, the parent node becomes equal to the left child as LIS will that be of the left child.
    • If cases where the length of left child < length of right child, the parent node becomes equal to the right child as LIS will that be of the right child.
    • If cases where the length of left child = length of right child, the parent node becomes equal to the sum of the count of LIS of the left child and the right child.
  • The required answer is the 2nd element of the root of the segment tree.

Below is the implementation of the above approach:

C++




// C++ implementation of the above approach
#include <bits/stdc++.h>
using namespace std;
 
#define M 100000
 
// Stores the Segemnt tree
vector<pair<int, int> > tree(4 * M + 1);
 
// Function to update Segment tree, the root
// of which contains the length of the LIS
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[idx].first
            = max(tree[idx].first, length_t);
        tree[idx].second = 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[2 * idx].first
        == tree[2 * idx + 1].first) {
        tree[idx].first
            = tree[2 * idx].first;
        tree[idx].second
            = tree[2 * idx].second
              + tree[2 * idx + 1].second;
    }
 
    // If length_t of left > length_t right child
    else if (tree[2 * idx].first
             > tree[2 * idx + 1].first) {
        tree[idx] = tree[2 * idx];
    }
 
    // If length_t of left < length_t right child
    else {
        tree[idx] = tree[2 * idx + 1];
    }
}
 
// Function to find the LIS length
// and count in the given range
pair<int, int> 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 tree[idx];
    }
 
    // If intervals are not overlapping
    pair<int, int> temp({ INT32_MIN, 0 });
    if (end < query_start
        || query_end < start) {
        return temp;
    }
 
    // If intervals are partially overlapping
    int mid = (start + end) / 2;
    auto left_child
        = query(start, mid, query_start,
                query_end, 2 * idx);
    auto 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.first > right_child.first) {
        return left_child;
    }
 
    // If length_t of right child is
    // greater than length_t of left child
    if (right_child.first > left_child.first) {
        return right_child;
    }
 
    // If length_t of left
    // and right child are equal
    // return there sum
    return make_pair(left_child.first,
                     left_child.second
                         + right_child.second);
}
 
// Comparator function to sort an array of pairs
// in increasing order of their 1st element and
// thereafter in decreasing order of the 2nd
bool comp(pair<int, int> a, pair<int, int> b)
{
    if (a.first == b.first) {
        return a.second > b.second;
    }
    return a.first < b.first;
}
 
// Function to find count
// of LIS in the given array
int countLIS(int arr[], int n)
{
    // Generating value-index pair array
    vector<pair<int, int> > pair_array(n);
    for (int i = 0; i < n; i++) {
        pair_array[i].first = arr[i];
        pair_array[i].second = i;
    }
 
    // Sort array of pairs with increasing order
    // of value and decreasing order of index
    sort(pair_array.begin(),
         pair_array.end(), comp);
 
    // Traverse the array
    // and perform query updates
    for (int i = 0; i < n; i++) {
 
        int update_idx = pair_array[i].second;
 
        // 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]
        pair<int, int> temp
            = query(0, n - 1, 0,
                    update_idx - 1, 1);
 
        // Update the segment tree
        update_tree(0, n - 1, update_idx,
                    temp.first + 1,
                    max(1, temp.second), 1);
    }
 
    // Stores the final answer
    pair<int, int> ans
        = query(0, n - 1, 0, n - 1, 1);
 
    // Return answer
    return ans.second;
}
 
// Driver Code
int main()
{
    int arr[] = { 1, 3, 5, 4, 7 };
    int n = sizeof(arr) / sizeof(int);
 
    cout << countLIS(arr, n);
 
    return 0;
}

Javascript




<script>
// Javascript implementation of the above approach
 
 
let M = 100000
 
// Stores the Segemnt tree
let tree = new Array(4 * M + 1).fill(0).map(() => []);
 
// Function to update Segment tree, the root
// of which contains the length of the LIS
function update_tree(start, end, update_idx, length_t, count_c, idx) {
  // If the intervals
  // are overlapping completely
  if (start == end
    && start == update_idx) {
    tree[idx][0]
      = Math.max(tree[idx][0], length_t);
    tree[idx][1] = count_c;
    return;
  }
 
  // If intervals are not overlapping
  if (update_idx < start
    || end < update_idx) {
    return;
  }
 
  // If intervals are partially overlapping
  let mid = Math.floor((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[2 * idx][0]
    == tree[2 * idx + 1][0]) {
    tree[idx][0]
      = tree[2 * idx][0];
    tree[idx][1]
      = tree[2 * idx][1]
      + tree[2 * idx + 1][1];
  }
 
  // If length_t of left > length_t right child
  else if (tree[2 * idx][0]
    > tree[2 * idx + 1][0]) {
    tree[idx] = tree[2 * idx];
  }
 
  // If length_t of left < length_t right child
  else {
    tree[idx] = tree[2 * idx + 1];
  }
}
 
// Function to find the LIS length
// and count in the given range
function query(start, end, query_start, query_end, idx) {
  // If the intervals
  // are overlapping completely
  if (query_start <= start
    && end <= query_end) {
    return tree[idx];
  }
 
  // If intervals are not overlapping
  let temp = [Number.MIN_SAFE_INTEGER, 0];
  if (end < query_start
    || query_end < start) {
    return temp;
  }
 
  // If intervals are partially overlapping
  let mid = Math.floor((start + end) / 2);
  let left_child
    = query(start, mid, query_start,
      query_end, 2 * idx);
  let 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[0] > right_child[0]) {
    return left_child;
  }
 
  // If length_t of right child is
  // greater than length_t of left child
  if (right_child[0] > left_child[0]) {
    return right_child;
  }
 
  // If length_t of left
  // and right child are equal
  // return there sum
  return [left_child[0],
  left_child[1]
  + right_child[1]];
}
 
// Comparator function to sort an array of pairs
// in increasing order of their 1st element and
// thereafter in decreasing order of the 2nd
function comp(a, b) {
  if (a[0] == b[0]) {
    return a[1] > b[1];
  }
  return a[0] < b[0];
}
 
// Function to find count
// of LIS in the given array
function countLIS(arr, n) {
  // Generating value-index pair array
  let pair_array = new Array(n).fill(0).map(() => []);
  for (let i = 0; i < n; i++) {
    pair_array[i][0] = arr[i];
    pair_array[i][1] = i;
  }
 
  // Sort array of pairs with increasing order
  // of value and decreasing order of index
  pair_array.sort(comp);
 
  // Traverse the array
  // and perform query updates
  for (let i = 0; i < n; i++) {
 
    let update_idx = pair_array[i][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]
    let temp = query(0, n - 1, 0, update_idx - 1, 1);
 
    // Update the segment tree
    update_tree(0, n - 1, update_idx,
      temp[0] + 1,
      Math.max(1, temp[1]), 1);
  }
 
  // Stores the final answer
  let ans = query(0, n - 1, 0, n - 1, 1);
 
  // Return answer
  return ans[1];
}
 
// Driver Code
 
let arr = [1, 3, 5, 4, 7];
let n = arr.length;
 
document.write(countLIS(arr, n));
 
// This code is contributed by saurabh_jaiswal.
</script>
Output
2

Time Complexity: O(N*log N)
Auxiliary Space: O(N)




My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!