# String Range Queries to find the number of subsets equal to a given String

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

Type 1: 1 L x,
Indicates update Lth index of string S by character ‘x’.

Type 2: 2 L R str
Find the number of subsets in range L to R
which is equal to the string str modulo 1000000007.

Constraints :
|S| <= 100000,
M <= 100000,
1 <= L, R <= |S|,
|str| <= 26,
All characters in str are unique,
S & str consisting of lowercase latin letters.

Examples:

Input : N = 16, M = 3, S = “geeekkksgskeegks”
type = 2: L = 1, R = 7, str = “gek”
type = 1: index = 2, character = ‘x’
type = 2: L = 1, R = 7, str = “gek”
Output : 9 6 4
query2 : No of subsets in string S i range [1…7] that is equal to gek is 9.
query1 : string S is changed to gxeekkksgskeegks after second query.
query2 : No of subsets in string S i range [1…7] that is equal to gek is 6.

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

Naive Approach :

Query type 1: We will calculate the frequency of each character of the query string in the range [L…R] and then multiply all the calculated frequencies to get the desired result.
Query type 2: We will replace the i’th character of the string with the given character.

Time complexity : 0(m*n)

Efficient Approach :

1. Using Segment Tree we can perform both operations in log(n) time. Every node of segment tree will contain frequency of characters in range [L..R].
2. The function build takes n*log(n) time to create a segment tree with every node containing the frequency of characters of some segment of the string.
3. The function get returns a vector containing frequency of all characters. Multiplication of all frequency of the given query string modulo 1e9+7 gives the desired result.
4. The function update decreases the frequency of character placed earlier and increases the frequency of new character present in the nodes of the segment tree by one.

Below is the C++ implementation of the above approach:

## CPP

 `// C++ implementation of the approach ` `#include ` `using` `namespace` `std; ` `  `  `#define N 400005 ` `#define mod 1000000007 ` `  `  `vector <``int``> seg_tree[N]; ` `string str; ` `  `  `// A recursive function that constructs  ` `// Segment Tree for given string ` `void` `build(``int` `pos, ``int` `st, ``int` `en) ` `{ ` `  `  `    ``if` `(st == en) ` `    ``{ ` `        ``// Increment the frequency of character ` `        ``// by one if st is equal to en ` `        ``seg_tree[pos][str[st - 1] - ``'a'``]++; ` `        ``return` `; ` `    ``} ` ` `  `    ``int` `mid = st + en >> 1; ` `  `  `    ``// Build the segment tree for range st to mid ` `    ``build(2 * pos, st, mid); ` `  `  `    ``// Build the segment tree for range mid+1 to en ` `    ``build(2 * pos + 1, mid + 1, en); ` `  `  `    ``// It stores addition of frequency of  ` `    ``// characters of both of its child after ` `    ``// segment tree is build ` `    ``for` `(``int` `i = 0; i < 26; i++) ` `        ``seg_tree[pos][i] = seg_tree[2 * pos + 1][i] ` `                             ``+ seg_tree[2 * pos][i]; ` `  `  `} ` `  `  `// A utility function for  ` `// addition of two vectors ` `vector <``int``> add_two_result(vector <``int``> v1, ` `                                  ``vector <``int``> v2) ` `{ ` `    ``vector <``int``> added_vec(26); ` `  `  `    ``// Adding two vector and storing ` `    ``// it in another vector ` `    ``for` `(``int` `i = 0; i < 26; i++) ` `        ``added_vec[i] = v1[i] + v2[i]; ` `  `  `    ``// Returning final vector ` `    ``return` `added_vec; ` `  `  `} ` ` `  `// A recursive function that return vector ` `// which contains frequency of every character ` `vector <``int``> get(``int` `pos, ``int` `l, ``int` `r, ` `                               ``int` `st, ``int` `en) ` `{ ` `    ``// If segment of this node is  ` `    ``// outside the given range ` `    ``if` `(l > en || r < st) ` `    ``{ ` `        ``vector <``int``> empty(26, 0); ` `        ``return`  `empty; ` `    ``} ` `  `  `    ``// If segment of this node is a part ` `    ``// of given range, then return the  ` `    ``// frequency every character of the segment ` `    ``if` `(st >= l && en <= r) ` `    ``{ ` `        ``return` `seg_tree[pos]; ` `    ``} ` `  `  `    ``// getting mid of st and en ` `    ``int` `mid = st + en >> 1; ` `  `  `    ``//storing answer of left child n v1 ` `    ``vector <``int``> v1 = get(2 * pos, l,  ` `                                    ``r, st, mid); ` `    ``//storing answer of left child n v1 ` `    ``vector <``int``> v2 = get(2 * pos + 1,  ` `                             ``l, r, mid + 1, en); ` `  `  `    ``//returning the addition of both vectors ` `    ``return` `add_two_result(v1, v2); ` `  `  `} ` `  `  `// A recursive function that update  ` `// frequency of new and old character ` `void` `update(``int` `pos, ``int` `indx, ``int` `st, ` `                    ``int` `en, ``char` `pre, ``char` `cur) { ` `  `  `    ``// If segment of this node is ` `    ``// outside the given range ` `    ``if` `(indx > en || indx < st) ``return``; ` `     `  `    ``// Subtract frequency of previous character ` `    ``seg_tree[pos][pre - ``'a'``]--;  ` `  `  `    ``// Add frequency of new character ` `    ``seg_tree[pos][cur - ``'a'``]++;  ` `  `  `    ``if` `(st != en) ` `    ``{ ` `        ``int` `mid = st + en >> 1; ` `         `  `        ``// update left child ` `        ``update(2 * pos, indx, st, ` `                              ``mid, pre, cur);  ` `         `  `        ``// update right child ` `        ``update(2 * pos + 1, indx, ` `                       ``mid + 1, en, pre, cur);  ` `    ``} ` `  `  `} ` `  `  `// Utility function to  ` `// initialize seg_tree vector ` `void` `initialize() ` `{ ` `    ``for` `(``int` `i = 0; i < N; i++) ` `        ``seg_tree[i].resize(26, 0); ` `} ` `  `  `int` `count_frequency(string s, vector <``int``> v) ` `{ ` `    ``int` `ans = 1; ` `    ``// multiplying frequency of all  ` `    ``// characters in string hard ` `    ``for` `(``int` `i = 0; s[i]; i++) ` `        ``ans = (ans * v[s[i] - ``'a'``]) % mod; ` `  `  `    ``return` `ans; ` `} ` `  `  `// Driver Code ` `int` `main() ` `{ ` `    ``int` `n, q, ans; ` `    ``vector <``int``> v; ` `  `  `    ``n = 15; ` `    ``str = ``"haardhhardrddrd"``; ` `  `  `    ``//initialize and build the seg_tree vector ` `    ``initialize(); ` `    ``build(1, 1, n); ` `    ``string s = ``"hard"``;  ` `  `  `    ``// getting frequency of all  ` `    ``// characters from 1 to 5 ` `    ``v = get(1, 1, 5, 1, n); ` `  `  `    ``// Calling count_frequency ` `    ``ans = count_frequency(s, v); ` `  `  `    ``cout << ans << ``'\n'``; ` `  `  `    ``// Updating character at index 3 ` `    ``update(1, 3, 1, n, str, ``'x'``); ` `    ``str = ``'x'``; ` `  `  `    ``// getting frequency of all  ` `    ``// characters from 1 to 5 ` `    ``v = get(1, 1, 5, 1, n); ` `  `  `    ``//calling count_frequency ` `    ``ans = count_frequency(s, v); ` `  `  `    ``cout << ans << ``'\n'``; ` `  `  `    ``return` `0; ` `  `  `} `

## Java

 `// Java implementation of the approach  ` `import` `java.util.*; ` ` `  `class` `GFG { ` ` `  `    ``final` `static` `int` `N = ``400005``; ` `    ``final` `static` `int` `mod = ``1000000007``; ` ` `  `    ``static` `int``[][] seg_tree = ``new` `int``[N][``26``]; ` `    ``static` `StringBuilder str; ` ` `  `    ``// A recursive function that constructs ` `    ``// Segment Tree for given String ` `    ``static` `void` `build(``int` `pos, ``int` `st, ``int` `en) { ` ` `  `        ``if` `(st == en) { ` ` `  `            ``// Increment the frequency of character ` `            ``// by one if st is equal to en ` `            ``seg_tree[pos][str.charAt(st - ``1``) - ``'a'``]++; ` `            ``return``; ` `        ``} ` ` `  `        ``int` `mid = st + en >> ``1``; ` ` `  `        ``// Build the segment tree for range st to mid ` `        ``build(``2` `* pos, st, mid); ` ` `  `        ``// Build the segment tree for range mid+1 to en ` `        ``build(``2` `* pos + ``1``, mid + ``1``, en); ` ` `  `        ``// It stores addition of frequency of ` `        ``// characters of both of its child after ` `        ``// segment tree is build ` `        ``for` `(``int` `i = ``0``; i < ``26``; i++) ` `            ``seg_tree[pos][i] = seg_tree[``2` `* pos + ``1``][i] + seg_tree[``2` `* pos][i]; ` ` `  `    ``} ` ` `  `    ``// A utility function for ` `    ``// addition of two vectors ` `    ``static` `int``[] add_two_result(``int``[] v1, ``int``[] v2) { ` `        ``int``[] added_vec = ``new` `int``[``26``]; ` ` `  `        ``// Adding two vector and storing ` `        ``// it in another vector ` `        ``for` `(``int` `i = ``0``; i < ``26``; i++) ` `            ``added_vec[i] = v1[i] + v2[i]; ` ` `  `        ``// Returning final vector ` `        ``return` `added_vec; ` ` `  `    ``} ` ` `  `    ``// A recursive function that return vector ` `    ``// which contains frequency of every character ` `    ``static` `int``[] get(``int` `pos, ``int` `l, ``int` `r, ``int` `st, ``int` `en) { ` ` `  `        ``// If segment of this node is ` `        ``// outside the given range ` `        ``if` `(l > en || r < st) { ` `            ``int``[] empty = ``new` `int``[``26``]; ` `            ``return` `empty; ` `        ``} ` ` `  `        ``// If segment of this node is a part ` `        ``// of given range, then return the ` `        ``// frequency every character of the segment ` `        ``if` `(st >= l && en <= r) { ` `            ``return` `seg_tree[pos]; ` `        ``} ` ` `  `        ``// getting mid of st and en ` `        ``int` `mid = st + en >> ``1``; ` ` `  `        ``// storing answer of left child n v1 ` `        ``int``[] v1 = get(``2` `* pos, l, r, st, mid); ` ` `  `        ``// storing answer of left child n v1 ` `        ``int``[] v2 = get(``2` `* pos + ``1``, l, r, mid + ``1``, en); ` ` `  `        ``// returning the addition of both vectors ` `        ``return` `add_two_result(v1, v2); ` `    ``} ` ` `  `    ``// A recursive function that update ` `    ``// frequency of new and old character ` `    ``static` `void` `update(``int` `pos, ``int` `indx, ``int` `st, ``int` `en, ``char` `pre, ``char` `cur) { ` ` `  `        ``// If segment of this node is ` `        ``// outside the given range ` `        ``if` `(indx > en || indx < st) ` `            ``return``; ` ` `  `        ``// Subtract frequency of previous character ` `        ``seg_tree[pos][pre - ``'a'``]--; ` ` `  `        ``// Add frequency of new character ` `        ``seg_tree[pos][cur - ``'a'``]++; ` ` `  `        ``if` `(st != en) { ` `            ``int` `mid = st + en >> ``1``; ` ` `  `            ``// update left child ` `            ``update(``2` `* pos, indx, st, mid, pre, cur); ` ` `  `            ``// update right child ` `            ``update(``2` `* pos + ``1``, indx, mid + ``1``, en, pre, cur); ` `        ``} ` `    ``} ` ` `  `    ``static` `int` `count_frequency(String s, ``int``[] v) { ` `        ``int` `ans = ``1``; ` ` `  `        ``// multiplying frequency of all ` `        ``// characters in String hard ` `        ``for` `(``int` `i = ``0``; i < s.length(); i++) ` `            ``ans = (ans * v[s.charAt(i) - ``'a'``]) % mod; ` ` `  `        ``return` `ans; ` `    ``} ` ` `  `    ``// Driver Code ` `    ``public` `static` `void` `main(String[] args) { ` ` `  `        ``int` `n, q, ans; ` `        ``int``[] v; ` ` `  `        ``n = ``15``; ` `        ``str = ``new` `StringBuilder(``"haardhhardrddrd"``); ` ` `  `        ``build(``1``, ``1``, n); ` `        ``String s = ``"hard"``; ` ` `  `        ``// getting frequency of all ` `        ``// characters from 1 to 5 ` `        ``v = get(``1``, ``1``, ``5``, ``1``, n); ` ` `  `        ``// Calling count_frequency ` `        ``ans = count_frequency(s, v); ` ` `  `        ``System.out.println(ans); ` ` `  `        ``// Updating character at index 3 ` `        ``update(``1``, ``3``, ``1``, n, str.charAt(``2``), ``'x'``); ` `        ``str.setCharAt(``2``, ``'x'``); ` ` `  `        ``// getting frequency of all ` `        ``// characters from 1 to 5 ` `        ``v = get(``1``, ``1``, ``5``, ``1``, n); ` ` `  `        ``// calling count_frequency ` `        ``ans = count_frequency(s, v); ` ` `  `        ``System.out.println(ans); ` `    ``} ` `} ` ` `  `// This code is contributed by ` `// sanjeev2552 `

## Python3

 `# Python3 implementation of the approach ` `N ``=` `400005` `mod ``=` `1000000007` ` `  `seg_tree ``=` `[[``0` `for` `i ``in` `range``(``26``)] ``for` `i ``in` `range``(N)] ` `str` `=` `"" ` ` `  `# A recursive function that constructs ` `# Segment Tree for given ` `def` `build(pos, st, en): ` ` `  `    ``if` `(st ``=``=` `en): ` ` `  `        ``# Increment the frequency of character ` `        ``# by one if st is equal to en ` `        ``seg_tree[pos][``ord``(``str``[st ``-` `1``] )``-` `ord``(``'a'``)]``+``=``1` `        ``return` ` `  `    ``mid ``=` `st ``+` `en >> ``1` ` `  `    ``# Build the segment tree for range st to mid ` `    ``build(``2` `*` `pos, st, mid) ` ` `  `    ``# Build the segment tree for range mid+1 to en ` `    ``build(``2` `*` `pos ``+` `1``, mid ``+` `1``, en) ` ` `  `    ``# It stores addition of frequency of ` `    ``# characters of both of its child after ` `    ``# segment tree is build ` `    ``for` `i ``in` `range``(``26``): ` `        ``seg_tree[pos][i] ``=` `seg_tree[``2` `*` `pos ``+` `1``][i] ``+` `\ ` `                            ``seg_tree[``2` `*` `pos][i] ` ` `  `# A utility function for ` `# addition of two vectors ` `def` `add_two_result(v1,v2): ` ` `  `    ``added_vec``=``[``0``]``*``(``26``) ` ` `  `    ``# Adding two vector and storing ` `    ``# it in another vector ` `    ``for` `i ``in` `range``(``26``): ` `        ``added_vec[i] ``=` `v1[i] ``+` `v2[i] ` ` `  `    ``# Returning final vector ` `    ``return` `added_vec ` ` `  `# A recursive function that return vector ` `# which contains frequency of every character ` `def` `get(pos, l, r,st, en): ` ` `  `    ``# If segment of this node is ` `    ``# outside the given range ` `    ``if` `(l > en ``or` `r < st): ` `        ``empty ``=` `[``0``]``*``26` `        ``return` `empty ` ` `  `    ``# If segment of this node is a part ` `    ``# of given range, then return the ` `    ``# frequency every character of the segment ` `    ``if` `(st >``=` `l ``and` `en <``=` `r): ` ` `  `        ``return` `seg_tree[pos] ` ` `  `    ``# getting mid of st and en ` `    ``mid ``=` `st ``+` `en >> ``1` ` `  `    ``# storing answer of left child n v1 ` `    ``v1 ``=` `get(``2` `*` `pos, l,r, st, mid) ` `     `  `    ``# storing answer of left child n v1 ` `    ``v2 ``=` `get(``2` `*` `pos ``+` `1``,l, r, mid ``+` `1``, en) ` ` `  `    ``# returning the addition of both vectors ` `    ``return` `add_two_result(v1, v2) ` ` `  `# A recursive function that update ` `# frequency of new and old character ` `def` `update(pos, indx, st,en,pre,cur): ` ` `  `    ``# If segment of this node is ` `    ``# outside the given range ` `    ``if` `(indx > en ``or` `indx < st): ` `        ``return` ` `  `    ``# Subtract frequency of previous character ` `    ``seg_tree[pos][``ord``(pre) ``-` `ord``(``'a'``)]``-``=``1` ` `  `    ``# Add frequency of new character ` `    ``seg_tree[pos][``ord``(cur) ``-` `ord``(``'a'``)]``+``=``1` ` `  `    ``if` `(st !``=` `en): ` ` `  `        ``mid ``=` `st ``+` `en >> ``1` ` `  `        ``# update left child ` `        ``update(``2` `*` `pos,indx, st,mid, pre, cur) ` ` `  `        ``# update right child ` `        ``update(``2` `*` `pos ``+` `1``, indx,mid ``+` `1``, en, pre, cur) ` ` `  `def` `count_frequency(s,v): ` ` `  `    ``ans ``=` `1` `     `  `    ``# multiplying frequency of all ` `    ``# characters in hard ` `    ``i ``=` `0` `    ``while` `i < ``len``(s): ` `        ``ans ``=` `(ans ``*` `v[``ord``(s[i]) ``-` `ord``(``'a'``)]) ``%` `mod ` `        ``i ``+``=` `1` ` `  `    ``return` `ans ` ` `  `# Driver Code ` `if` `__name__ ``=``=` `'__main__'``: ` `    ``v``=``[] ` ` `  `    ``n ``=` `15` `    ``str` `=` `"haardhhardrddrd"` `    ``str``=``[i ``for` `i ``in` `str``] ` ` `  `    ``build(``1``, ``1``, n) ` `    ``s ``=` `"hard"` ` `  `    ``# getting frequency of all ` `    ``# characters from 1 to 5 ` `    ``v ``=` `get(``1``, ``1``, ``5``, ``1``, n) ` ` `  `    ``# Calling count_frequency ` `    ``ans ``=` `count_frequency(s, v) ` ` `  `    ``print``(ans) ` ` `  `    ``# Updating character at index 3 ` `    ``update(``1``, ``3``, ``1``, n, ``str``[``2``], ``'x'``) ` `    ``str``[``2``] ``=` `'x'` ` `  `    ``# getting frequency of all ` `    ``# characters from 1 to 5 ` `    ``v ``=` `get(``1``, ``1``, ``5``, ``1``, n) ` ` `  `    ``# calling count_frequency ` `    ``ans ``=` `count_frequency(s, v) ` ` `  `    ``print``(ans) ` ` `  `# This code is contributed by mohit kumar 29 `

Time complexity : 0(m*log(n)+n*log(n))

GeeksforGeeks has prepared a complete interview preparation course with premium videos, theory, practice problems, TA support and many more features. Please refer Placement 100 for details

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