String Range Queries to count number of distinct characters with updates

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].


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


Input: S = “abcdbbd” Q = 6
2 3 6
1 5 z
2 1 1
1 4 a
1 7 d
2 1 7
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

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(N2)

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 ).

  1. Insert all characters of the string with its index into Hash-map
  2. 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
  3. 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:






#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,               \
// 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.
    int previous = S[pos] - 'a';
    int current = c - 'a';
    S[pos] = c;
// 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;
    for (int i = 0; i < 26; i++) {
        int temp = lower_bound(hMap[i], L);
        if (temp <= R and temp != -1)
    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;




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


My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using or mail your article to 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.