 Open in App
Not now

# Queries to check if any non-repeating element exists within range [L, R] of an Array

• Difficulty Level : Medium
• Last Updated : 11 Jul, 2022

Given an array arr[] consisting of integers and queries Q of the form (L, R), the task is to check whether any non-repeating element is present within indices [L, R](1 based indexing) or not. If there is at least one non-repeating element, then print “Yes”. Otherwise, print “No”.

Examples:

Input: arr[] = {1, 2, 1, 2, 3, 4}, Queries[][] = {{1, 4}, {1, 5}}
Output: No Yes
Explanation:
For the first query, the subarray is {1, 2, 1, 2}, we can see that both number have frequency 2. Therefore, the answer is No.
For the second query, the subarray is {1, 2, 1, 2, 3}, we can see that 3 has frequency 1 so the answer is Yes.

Input: arr[] = {1, 2, 3, 4, 5}, Queries[][] = {{1, 4}}
Output: Yes
Explanation: The subarray is {1, 2, 3, 4}, has all elements as frequency 1 so the answer is Yes.

## Recommended: Please try your approach on {IDE} first, before moving on to the solution.

Naive Approach:
The simplest approach to solve the problem is to iterate over a given subarray for each query and maintain a map for storing the frequency of each element. Iterate over the map and check whether there is an element of frequency 1 or not.

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

Efficient Approach: The key observation for the solution is, for the element to have frequency 1 in the given array, the previous occurrence of this number in the array is strictly less than the query l and next occurrence of the element is strictly greater than r of some query. Use this observation to find order. Below are the steps that use the Merge Sort Tree approach to solve the given problem:

1. Store the previous occurrence and next occurrence of every ith element in the array as pair
2. Build the merge sort tree and merge nodes in them according to the previous occurrence. The merge function is used to merge the ranges.
3. At each node of merge sort tree, maintain prefix maximum on the next occurrence because we need as smallest possible previous occurrence and as big next occurrence of some element.
4. For answering the query, we need node with previous occurrence strictly less than l.
5. For the element in the merge sort tree with the previous occurrence less than l, find the max next occurrence and check if next occurrence is greater than r of the query, then there is an element present in the subarray with frequency 1.

Below is the implementation of the above approach:

## CPP

 `// C++ program for the above approach ` `#include ` `using` `namespace` `std; ` ` `  `const` `int` `INF = 1e9 + 9; ` `const` `int` `N = 1e5 + 5; ` ` `  `// Merge sort of pair type for storing ` `// prev and next occurrences of element ` `vector > > segtree(4 * N); ` ` `  `// Stores the occurrences ` `vector > occurrences(N); ` ` `  `// Finds occurrences ` `vector > pos(N); ` ` `  `int` `n; ` ` `  `// Function to build merge sort tree ` `void` `build(``int` `node = 0, ``int` `l = 0, ` `           ``int` `r = n - 1) ` `{ ` ` `  `    ``// For leaf node, push the prev & ` `    ``// next occurrence of the lth node ` `    ``if` `(l == r) { ` `        ``segtree[node].push_back(occurrences[l]); ` `        ``return``; ` `    ``} ` ` `  `    ``int` `mid = (l + r) / 2; ` ` `  `    ``// Left recursion call ` `    ``build(2 * node + 1, l, mid); ` ` `  `    ``// Right recursion call ` `    ``build(2 * node + 2, mid + 1, r); ` ` `  `    ``// Merging the left child and right child ` `    ``// according to the prev occurrence ` `    ``merge(segtree[2 * node + 1].begin(), ` `          ``segtree[2 * node + 1].end(), ` `          ``segtree[2 * node + 2].begin(), ` `          ``segtree[2 * node + 2].end(), ` `          ``back_inserter(segtree[node])); ` ` `  `    ``// Update the next occurrence ` `    ``// with prefix maximum ` `    ``int` `mx = 0; ` ` `  `    ``for` `(``auto``& i : segtree[node]) { ` ` `  `        ``// Update the maximum ` `        ``// next occurrence ` `        ``mx = max(mx, i.second); ` ` `  `        ``// Update the next occurrence ` `        ``// with prefix max ` `        ``i.second = mx; ` `    ``} ` `} ` ` `  `// Function to check whether an ` `// element is present from x to y ` `// with frequency 1 ` `bool` `query(``int` `x, ``int` `y, ``int` `node = 0, ` `           ``int` `l = 0, ``int` `r = n - 1) ` `{ ` `    ``// No overlap condition ` `    ``if` `(l > y || r < x || x > y) ` `        ``return` `false``; ` ` `  `    ``// Complete overlap condition ` `    ``if` `(x <= l && r <= y) { ` ` `  `        ``// Find the first node with ` `        ``// prev occurrence >= x ` `        ``auto` `it = lower_bound(segtree[node].begin(), ` `                              ``segtree[node].end(), ` `                              ``make_pair(x, -1)); ` ` `  `        ``// No element in this range with ` `        ``// previous occurrence less than x ` `        ``if` `(it == segtree[node].begin()) ` `            ``return` `false``; ` ` `  `        ``else` `{ ` ` `  `            ``it--; ` ` `  `            ``// Check if the max next ` `            ``// occurrence is greater ` `            ``// than y or not ` `            ``if` `(it->second > y) ` `                ``return` `true``; ` `            ``else` `                ``return` `false``; ` `        ``} ` `    ``} ` ` `  `    ``int` `mid = (l + r) / 2; ` `    ``bool` `a = query(x, y, 2 * node + 1, l, mid); ` `    ``bool` `b = query(x, y, 2 * node + 2, mid + 1, r); ` ` `  `    ``// Return if any of the ` `    ``// children returned true ` `    ``return` `(a | b); ` `} ` ` `  `// Function do preprocessing that ` `// is finding the next and previous ` `// occurrences ` `void` `preprocess(``int` `arr[]) ` `{ ` ` `  `    ``// Store the position of ` `    ``// every element ` `    ``for` `(``int` `i = 0; i < n; i++) { ` `        ``pos[arr[i]].insert(i); ` `    ``} ` ` `  `    ``for` `(``int` `i = 0; i < n; i++) { ` ` `  `        ``// Find the previous ` `        ``// and next occurrences ` `        ``auto` `it = pos[arr[i]].find(i); ` `        ``if` `(it == pos[arr[i]].begin()) ` `            ``occurrences[i].first = -INF; ` ` `  `        ``else` `            ``occurrences[i].first = *prev(it); ` ` `  `        ``// Check if there is no next occurrence ` `        ``if` `(next(it) == pos[arr[i]].end()) ` ` `  `            ``occurrences[i].second = INF; ` `        ``else` `            ``occurrences[i].second = *next(it); ` `    ``} ` ` `  `    ``// Building the merge sort tree ` `    ``build(); ` `} ` ` `  `// Function to find whether there is a ` `// number in the subarray with 1 frequency ` `void` `answerQueries(``int` `arr[], ` `                   ``vector >& queries) ` `{ ` `    ``preprocess(arr); ` ` `  `    ``// Answering the queries ` `    ``for` `(``int` `i = 0; i < queries.size(); i++) { ` `        ``int` `l = queries[i].first - 1; ` `        ``int` `r = queries[i].second - 1; ` ` `  `        ``bool` `there = query(l, r); ` ` `  `        ``if` `(there == ``true``) ` `            ``cout << ``"Yes\n"``; ` ` `  `        ``else` `            ``cout << ``"No\n"``; ` `    ``} ` `} ` ` `  `// Driver Code ` `int` `main() ` `{ ` `    ``int` `arr[] = { 1, 2, 1, 2, 3, 4 }; ` `    ``n = ``sizeof``(arr) / ``sizeof``(arr); ` ` `  `    ``vector > queries = { { 1, 4 }, { 1, 5 } }; ` ` `  `    ``answerQueries(arr, queries); ` `} `

Output:

```No
Yes
```

Time Complexity: O(N*log(N) + Q*log2(N))
Auxiliary Space: O(N*log(N))

Related Topic: Segment Tree

My Personal Notes arrow_drop_up
Related Articles