Given a string S of length N, and Q queries of the following type:

Type 1:1 i X

Update the i-th character of the string with the given character, X.

Type 2:L R

Count number of distinct characters in the given range [L, R].Constraint:

- 1<=N<=500000
- 1<=Q<20000
- |S|=N
- String S contains only lowercase alphabets.

**Examples:**

Input:S = “abcdbbd” Q = 6

2 3 6

1 5 z

2 1 1

1 4 a

1 7 d

2 1 7

Output:

3

1

5

Explanation:

For the Queries:

1. L = 3, R = 6

The different characters are:c, b, d.

ans = 3.

2. String after query updated as S=”abcdzbd”.

3. L = 1, R = 1

Only one different character.

and so on process all queries.

Input:S = “aaaaa”, Q = 2

1 2 b

2 1 4

Output:

2

**Naive approach:**

**Query type 1:** Replace i-th character of the string with the given character.

**Query type 2:** Traverse the string from L to R and count number of distinct characters.

**Time complexity: ** O(N^{2})

**Efficient approach:** This approach is based on the Frequency-counting algorithm.

The idea is to use a HashMap to map distinct characters of the string with an Ordered_set which stores indices of its all occurrence. Ordered_set is used because it is based on Red-Black tree, so insertion and deletion of character will taken O ( log N ).

- Insert all characters of the string with its index into Hash-map
- For query of type 1, erase the occurrence of character at index i and insert occurrence of character X at index i in Hash-map
- For query of type 2, traverse all 26 characters and check if its occurrence is within the range [L, R], if yes then increment the count. After traversing print the value of count.

Below is the implementation of the above approach:

## C++

`#include <bits/stdc++.h> ` `using` `namespace` `std; ` ` ` `#include <ext/pb_ds/assoc_container.hpp> ` `#include <ext/pb_ds/tree_policy.hpp> ` `using` `namespace` `__gnu_pbds; ` ` ` `#define ordered_set \ ` ` ` `tree<` `int` `, null_type, less<` `int` `>, \ ` ` ` `rb_tree_tag, \ ` ` ` `tree_order_statistics_node_update> ` ` ` `// Function that returns the lower- ` `// bound of the element in ordered_set ` `int` `lower_bound(ordered_set set1, ` `int` `x) ` `{ ` ` ` `// Finding the position of ` ` ` `// the element ` ` ` `int` `pos = set1.order_of_key(x); ` ` ` ` ` `// If the element is not ` ` ` `// present in the set ` ` ` `if` `(pos == set1.size()) { ` ` ` `return` `-1; ` ` ` `} ` ` ` ` ` `// Finding the element at ` ` ` `// the position ` ` ` `else` `{ ` ` ` `int` `element = *(set1.find_by_order(pos)); ` ` ` ` ` `return` `element; ` ` ` `} ` `} ` ` ` `// Utility function to add the ` `// position of all characters ` `// of string into ordered set ` `void` `insert( ` ` ` `unordered_map<` `int` `, ordered_set>& hMap, ` ` ` `string S, ` `int` `N) ` `{ ` ` ` `for` `(` `int` `i = 0; i < N; i++) { ` ` ` `hMap[S[i] - ` `'a'` `].insert(i); ` ` ` `} ` `} ` ` ` `// Utility function for update ` `// the character at position P ` `void` `Query1( ` ` ` `string& S, ` ` ` `unordered_map<` `int` `, ordered_set>& hMap, ` ` ` `int` `pos, ` `char` `c) ` `{ ` ` ` ` ` `// we delete the position of the ` ` ` `// previous character as new ` ` ` `// character is to be replaced ` ` ` `// at the same position. ` ` ` `pos--; ` ` ` `int` `previous = S[pos] - ` `'a'` `; ` ` ` `int` `current = c - ` `'a'` `; ` ` ` `S[pos] = c; ` ` ` `hMap[previous].erase(pos); ` ` ` `hMap[current].insert(pos); ` `} ` ` ` `// Utility function to determine ` `// number of different characters ` `// in given range. ` `void` `Query2( ` ` ` `unordered_map<` `int` `, ordered_set>& hMap, ` ` ` `int` `L, ` `int` `R) ` `{ ` ` ` `// Iterate over all 26 alphabets ` ` ` `// and check if it is in given ` ` ` `// range using lower bound. ` ` ` `int` `count = 0; ` ` ` `L--; ` ` ` `R--; ` ` ` `for` `(` `int` `i = 0; i < 26; i++) { ` ` ` `int` `temp = lower_bound(hMap[i], L); ` ` ` `if` `(temp <= R and temp != -1) ` ` ` `count++; ` ` ` `} ` ` ` `cout << count << endl; ` `} ` ` ` `// Driver code ` `int` `main() ` `{ ` ` ` `string S = ` `"abcdbbd"` `; ` ` ` `int` `N = S.size(); ` ` ` ` ` `unordered_map<` `int` `, ordered_set> hMap; ` ` ` ` ` `// Insert all characters with its ` ` ` `// occurrence in the hash map ` ` ` `insert(hMap, S, N); ` ` ` ` ` `// Queries for sample input ` ` ` `Query2(hMap, 3, 6); ` ` ` `Query1(S, hMap, 5, ` `'z'` `); ` ` ` `Query2(hMap, 1, 1); ` ` ` `Query1(S, hMap, 4, ` `'a'` `); ` ` ` `Query1(S, hMap, 7, ` `'d'` `); ` ` ` `Query2(hMap, 1, 7); ` ` ` ` ` `return` `0; ` `} ` |

*chevron_right*

*filter_none*

**Output:**

3 1 5

Time complexity: **O(Q * logN)** where Q is number of queries and N is the size of the string.

## Recommended Posts:

- Count of distinct characters in a substring by given range for Q queries
- Range Queries to count the number of even parity values with updates
- Array range queries to count the number of Fibonacci numbers with updates
- Array Range Queries to count Powerful numbers with updates
- Queries for count of array elements with values in given range with updates
- Range Queries for number of Armstrong numbers in an array with updates
- Array Range Queries to find the Maximum Armstrong number with updates
- Array range queries to find the maximum Fibonacci number with updates
- Array range queries to find the number of perfect square elements with updates
- Queries to count characters having odd frequency in a range [L, R]
- Count of ungrouped characters after dividing a string into K groups of distinct characters
- Range sum queries without updates
- Count of distinct numbers in an Array in a range for Online Queries using Merge Sort Tree
- C++ Program for Range sum queries without updates
- Queries to find maximum product pair in range with updates
- Binary Indexed Tree : Range Updates and Point Queries
- Check whether count of distinct characters in a string is Prime or not
- Dynamic Segment Trees : Online Queries for Range Sum with Point Updates
- Count of Distinct strings possible by inserting K characters in the original string
- Count ways to partition a string such that both parts have equal distinct characters

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.