Skip to content
Related Articles
Queries to calculate sum of squares of ASCII values of characters of a substring with updates
• Difficulty Level : Expert
• Last Updated : 26 May, 2021

Given a string S of length N and a 2D array of strings Q[][] consisting of M queries of the following type:

• Query(“U”, “I”, “X”): Update the character at index I with the character X.
• Query(“S”, “L”, “R”): Print the sum of the squares of the position of the characters in the substring {S[L], …., S[R]} according to the English alphabets.

Examples:

Input: S = “geeksforgeeks”, Q[][] = {{“S”, “0”, “2”}, {“S”, “1”, “2”}, {“U”, “1”, “a”}, {“S”, “0”, “2”}, {“S”, “4”, “5”}}
Output:
99
50
75
397
Explanation:
For Query(“S”, “0”, “2”), sum of squares of the positions of the characters in the substring “gee” = 7*7 + 5*5 + 5*5 = 99.
For Query(“S”, “1”, “2”), sum of squares of the positions of the character in the substring “ee” = 5*5 + 5*5 = 50.
For Query(“U”, “1”, “a”): Replacing S by ‘a’ modifies S to “gaeksforgeeks”.
For Query(“S”, “0”, “2”), sum of squares of the positions of the characters in the substring “gae” = 7*7 + 1*1 + 5*5 = 75.
For Query(“S”, “4”, “5”), sum of squares of the positions of the characters in the substring “ks” = 19*19 + 36 = 397

Input: S = “geeksforgeeks”, Q[][] = {{“S”, “1”, “2”}}
Output: 50

Naive Approach: The simplest approach to solve the problem is to traverse the array Q[][] for each query and for queries of type ‘S’, simply traverse the substring {S[L], …, S[R]} and print the sum of squares of the positions of the characters in English alphabets. In each iteration to perform the query of type ‘U’, simply assign X to S[I].

Time Complexity: O(N * M)
Auxiliary Space: O(1)

Efficient Approach: The above approach can be optimized by using Segment Tree data structure. Follow the steps below to solve the problem:

• Initialize a segment tree, say tree[], where each node stores the sum of squares of the position of the characters in English alphabets in its subtree.
• For Query(“U”, “I”, “X”), define an update function, similar to the update function of sum range queries. Update S[i] = X and then call the update() function to update the segment tree.
• For Query(“S”, “L”, “R”), define a function query(), similar to sum range query and then, print the sum obtained by calling the query() function for the substring {S[L], …., S[R]}.

Below is the implementation of the above approach:

## C++

 `// C++ implementation of``// the above approach``#include ``using` `namespace` `std;` `// Structure of a node``// of a Segment Tree``struct` `treeNode {``    ``int` `square_sum;``};` `// Function to construct the Segment Tree``void` `buildTree(string s, treeNode* tree,``               ``int` `start, ``int` `end,``               ``int` `treeNode)``{``    ``// If start and end are equal``    ``if` `(start == end) {` `        ``// Assign squares of positions``        ``// of the characters``        ``tree[treeNode].square_sum``            ``= ``pow``(s[start] - ``'a'` `+ 1, 2);` `        ``return``;``    ``}` `    ``// Stores the mid value of``    ``// the range [start, end]``    ``int` `mid = start + ((end - start) / 2);` `    ``// Recursive call to left subtree``    ``buildTree(s, tree, start,``              ``mid, 2 * treeNode);` `    ``// Recursive call to right subtree``    ``buildTree(s, tree, mid + 1,``              ``end, 1 + 2 * treeNode);` `    ``// Update the current node``    ``tree[treeNode].square_sum``        ``= tree[(2 * treeNode)].square_sum``          ``+ tree[(2 * treeNode) + 1].square_sum;``}` `// Function to perform the queries of type 2``int` `querySquareSum(treeNode* tree, ``int` `start,``                   ``int` `end, ``int` `treeNode,``                   ``int` `l, ``int` `r)``{``    ``// No overlap``    ``if` `((l > end) || (r < start)) {``        ``return` `0;``    ``}` `    ``// If l <= start and r >= end``    ``if` `((l <= start) && (r >= end)) {` `        ``// Return the value of treeNode``        ``return` `tree[treeNode].square_sum;``    ``}` `    ``// Calculate middle of the range [start, end]``    ``int` `mid = start + ((end - start) / 2);` `    ``// Function call to left subtree``    ``int` `X = querySquareSum(tree, start,``                           ``mid, 2 * treeNode,``                           ``l, r);` `    ``// Function call to right subtree``    ``int` `Y = +querySquareSum(tree, mid + 1, end,``                            ``1 + 2 * treeNode, l, r);` `    ``// Return the sum of X and Y``    ``return` `X + Y;``}` `// Function to perform update``// queries on a Segment Tree``void` `updateTree(string s, treeNode* tree,``                ``int` `start, ``int` `end,``                ``int` `treeNode, ``int` `idx, ``char` `X)``{``    ``// If start is equal to end``    ``// and idx is equal to start``    ``if` `((start == end) && (idx == start)) {` `        ``// Base Case``        ``s[idx] = X;``        ``tree[treeNode].square_sum``            ``= ``pow``(X - ``'a'` `+ 1, 2);` `        ``return``;``    ``}` `    ``// Calculate middle of the range [start, end]``    ``int` `mid = start + ((end - start) / 2);` `    ``// If idx <=  mid``    ``if` `(idx <= mid) {` `        ``// Function call to left subtree``        ``updateTree(s, tree, start, mid,``                   ``(2 * treeNode), idx, X);``    ``}` `    ``// Otherwise``    ``else` `{` `        ``// Function call to the right subtree``        ``updateTree(s, tree, mid + 1, end,``                   ``(2 * treeNode) + 1, idx, X);``    ``}` `    ``// Update the current node``    ``tree[treeNode].square_sum``        ``= tree[(2 * treeNode)].square_sum``          ``+ tree[(2 * treeNode) + 1].square_sum;``}` `// Function to perform the given queries``void` `PerformQuery(string S,``                  ``vector > Q)``{``    ``int` `n = S.size();` `    ``// Stores the segment tree``    ``treeNode* tree = ``new` `treeNode[(4 * n) + 1];` `    ``// Traverse the segment tree``    ``for` `(``int` `i = 0; i <= (4 * n); i = i + 1) {` `        ``// Assign 0 to each node``        ``tree[i].square_sum = 0;``    ``}` `    ``// Builds segment tree``    ``buildTree(S, tree, 0, n - 1, 1);` `    ``// Traverse the query array Q[][]``    ``for` `(``int` `i = 0; i < Q.size(); i++) {` `        ``// If query is of type S``        ``if` `(Q[i] == ``"S"``) {` `            ``// Stores the left boundary``            ``int` `L = stoi(Q[i]);` `            ``// Stores the right boundary``            ``int` `R = stoi(Q[i]);` `            ``// Prints the sum of squares of the``            ``// alphabetic positions of the characters``            ``cout << querySquareSum(tree, 0,``                                   ``n - 1, 1, L, R)``                 ``<< endl;``        ``}` `        ``// Otherwise``        ``else` `if` `(Q[i] == ``"U"``) {` `            ``// Stores the index of the``            ``// character to be updated``            ``int` `I = stoi(Q[i]);` `            ``// Update the segment tree``            ``updateTree(S, tree, 0, n - 1,``                       ``1, I, Q[i]);``        ``}``    ``}``}` `// Driver Code``int` `main()``{``    ``// Input``    ``string S = ``"geeksforgeeks"``;``    ``vector > Q = { { ``"S"``, ``"0"``, ``"2"` `},``                                  ``{ ``"S"``, ``"1"``, ``"2"` `},``                                  ``{ ``"U"``, ``"1"``, ``"a"` `},``                                  ``{ ``"S"``, ``"0"``, ``"2"` `},``                                  ``{ ``"S"``, ``"4"``, ``"5"` `} };``    ``// Function call``    ``PerformQuery(S, Q);``}`

## Java

 `// Java implementation of``// the above approach``import` `java.io.*;``import` `java.lang.*;``import` `java.util.*;` `class` `GFG{` `// Structure of a node``// of a Segment Tree``static` `class` `treeNode``{``    ``int` `square_sum;` `    ``treeNode(``int` `square_sum)``    ``{``        ``this``.square_sum = square_sum;``    ``}``};` `// Function to construct the Segment Tree``static` `void` `buildTree(``char` `s[], treeNode tree[],``                      ``int` `start, ``int` `end, ``int` `treenode)``{``    ` `    ``// If start and end are equal``    ``if` `(start == end)``    ``{``        ` `        ``// Assign squares of positions``        ``// of the characters``        ``tree[treenode].square_sum = (``int``)Math.pow(``            ``s[start] - ``'a'` `+ ``1``, ``2``);` `        ``return``;``    ``}` `    ``// Stores the mid value of``    ``// the range [start, end]``    ``int` `mid = start + ((end - start) / ``2``);` `    ``// Recursive call to left subtree``    ``buildTree(s, tree, start, mid, ``2` `* treenode);` `    ``// Recursive call to right subtree``    ``buildTree(s, tree, mid + ``1``, end, ``1` `+ ``2` `* treenode);` `    ``// Update the current node``    ``tree[treenode].square_sum = tree[(``2` `* treenode)].square_sum +``                                ``tree[(``2` `* treenode) + ``1``].square_sum;``}` `// Function to perform the queries of type 2``static` `int` `querySquareSum(treeNode tree[], ``int` `start,``                          ``int` `end, ``int` `treenode, ``int` `l,``                          ``int` `r)``{``    ` `    ``// No overlap``    ``if` `((l > end) || (r < start))``    ``{``        ``return` `0``;``    ``}` `    ``// If l <= start and r >= end``    ``if` `((l <= start) && (r >= end))``    ``{` `        ``// Return the value of treeNode``        ``return` `tree[treenode].square_sum;``    ``}` `    ``// Calculate middle of the range [start, end]``    ``int` `mid = start + ((end - start) / ``2``);` `    ``// Function call to left subtree``    ``int` `X = querySquareSum(tree, start, mid,``                           ``2` `* treenode, l, r);` `    ``// Function call to right subtree``    ``int` `Y = +querySquareSum(tree, mid + ``1``, end,``                            ``1` `+ ``2` `* treenode, l, r);` `    ``// Return the sum of X and Y``    ``return` `X + Y;``}` `// Function to perform update``// queries on a Segment Tree``static` `void` `updateTree(``char` `s[], treeNode tree[],``                       ``int` `start, ``int` `end, ``int` `treenode,``                       ``int` `idx, ``char` `X)``{``    ` `    ``// If start is equal to end``    ``// and idx is equal to start``    ``if` `((start == end) && (idx == start))``    ``{``        ` `        ``// Base Case``        ``s[idx] = X;``        ``tree[treenode].square_sum = (``int``)Math.pow(``            ``X - ``'a'` `+ ``1``, ``2``);` `        ``return``;``    ``}` `    ``// Calculate middle of the range [start, end]``    ``int` `mid = start + ((end - start) / ``2``);` `    ``// If idx <=  mid``    ``if` `(idx <= mid)``    ``{``        ` `        ``// Function call to left subtree``        ``updateTree(s, tree, start, mid, (``2` `* treenode),``                   ``idx, X);``    ``}` `    ``// Otherwise``    ``else``    ``{` `        ``// Function call to the right subtree``        ``updateTree(s, tree, mid + ``1``, end,``                 ``(``2` `* treenode) + ``1``, idx, X);``    ``}` `    ``// Update the current node``    ``tree[treenode].square_sum = tree[(``2` `* treenode)].square_sum +``                                ``tree[(``2` `* treenode) + ``1``].square_sum;``}` `// Function to perform the given queries``static` `void` `PerformQuery(String S, String Q[][])``{``    ``int` `n = S.length();` `    ``// Stores the segment tree``    ``treeNode tree[] = ``new` `treeNode[(``4` `* n) + ``1``];` `    ``// Traverse the segment tree``    ``for``(``int` `i = ``0``; i <= (``4` `* n); i = i + ``1``)``    ``{``        ` `        ``// Assign 0 to each node``        ``tree[i] = ``new` `treeNode(``0``);``    ``}` `    ``char` `s[] = S.toCharArray();` `    ``// Builds segment tree``    ``buildTree(s, tree, ``0``, n - ``1``, ``1``);` `    ``// Traverse the query array Q[][]``    ``for``(``int` `i = ``0``; i < Q.length; i++)``    ``{``        ` `        ``// If query is of type S``        ``if` `(Q[i][``0``] == ``"S"``)``        ``{``            ` `            ``// Stores the left boundary``            ``int` `L = Integer.parseInt(Q[i][``1``]);` `            ``// Stores the right boundary``            ``int` `R = Integer.parseInt(Q[i][``2``]);` `            ``// Prints the sum of squares of the``            ``// alphabetic positions of the characters``            ``System.out.println(querySquareSum(``                ``tree, ``0``, n - ``1``, ``1``, L, R));``        ``}` `        ``// Otherwise``        ``else` `if` `(Q[i][``0``] == ``"U"``)``        ``{``            ` `            ``// Stores the index of the``            ``// character to be updated``            ``int` `I = Integer.parseInt(Q[i][``1``]);` `            ``// Update the segment tree``            ``updateTree(s, tree, ``0``, n - ``1``, ``1``, I,``                       ``Q[i][``2``].charAt(``0``));``        ``}``    ``}``}` `// Driver Code``public` `static` `void` `main(String[] args)``{` `    ``// Input``    ``String S = ``"geeksforgeeks"``;``    ``String Q[][] = { { ``"S"``, ``"0"``, ``"2"` `},``                     ``{ ``"S"``, ``"1"``, ``"2"` `},``                     ``{ ``"U"``, ``"1"``, ``"a"` `},``                     ``{ ``"S"``, ``"0"``, ``"2"` `},``                     ``{ ``"S"``, ``"4"``, ``"5"` `} };``    ``// Function call``    ``PerformQuery(S, Q);``}``}` `// This code is contributed by Kingash`

## Python3

 `# Python3 implementation of``# the above approach` `# Structure of a node``# of a Segment Tree``class` `treeNode:``    ` `    ``def` `__init__(``self``, x):``        ` `        ``self``.square_sum ``=` `x` `# Function to construct the Segment Tree``def` `buildTree(s, tree, start, end, treeNode):``    ` `    ``# If start and end are equa``    ``if` `(start ``=``=` `end):` `        ``# Assign squares of positions``        ``# of the characters``        ``tree[treeNode].square_sum ``=` `pow``(``ord``(s[start]) ``-``                                        ``ord``(``'a'``) ``+` `1``, ``2``)` `        ``return` `    ``# Stores the mid value of``    ``# the range [start, end]``    ``mid ``=` `start ``+` `((end ``-` `start) ``/``/` `2``)` `    ``# Recursive call to left subtree``    ``buildTree(s, tree, start, mid, ``2` `*` `treeNode)` `    ``# Recursive call to right subtree``    ``buildTree(s, tree, mid ``+` `1``, end,``                         ``1` `+` `2` `*` `treeNode)` `    ``# Update the current node``    ``tree[treeNode].square_sum ``=` `(tree[(``2` `*` `treeNode)].square_sum ``+``                                 ``tree[(``2` `*` `treeNode) ``+` `1``].square_sum)` `# Function to perform the queries of type 2``def` `querySquareSum(tree, start, end, treeNode, l, r):``    ` `    ``# No overlap``    ``if` `((l > end) ``or` `(r < start)):``        ``return` `0` `    ``# If l <= start and r >= end``    ``if` `((l <``=` `start) ``and` `(r >``=` `end)):``        ` `        ``# Return the value of treeNode``        ``return` `tree[treeNode].square_sum` `    ``# Calculate middle of the range [start, end]``    ``mid ``=` `start ``+` `((end ``-` `start) ``/``/` `2``)` `    ``# Function call to left subtree``    ``X ``=` `querySquareSum(tree, start, mid,``                       ``2` `*` `treeNode, l, r)` `    ``# Function call to right subtree``    ``Y ``=` `+``querySquareSum(tree, mid ``+` `1``, end,``                                ``1` `+` `2` `*` `treeNode, l, r)` `    ``# Return the sum of X and Y``    ``return` `X ``+` `Y` `# Function to perform update``# queries on a Segment Tree``def` `updateTree(s, tree, start, end, treeNode, idx, X):``    ` `    ``# If start is equal to end``    ``# and idx is equal to start``    ``if` `((start ``=``=` `end) ``and` `(idx ``=``=` `start)):` `        ``# Base Case``        ``s[idx] ``=` `X``        ``tree[treeNode].square_sum ``=` `pow``(``ord``(X) ``-``                                       ``ord``(``'a'``) ``+` `1``, ``2``)``        ``return` `    ``# Calculate middle of the range [start, end]``    ``mid ``=` `start ``+` `((end ``-` `start) ``/``/` `2``)` `    ``# If idx <=  mid``    ``if` `(idx <``=` `mid):``        ` `        ``# Function call to left subtree``        ``updateTree(s, tree, start, mid,``                  ``(``2` `*` `treeNode), idx, X)``                  ` `    ``# Otherwise``    ``else``:` `        ``# Function call to the right subtree``        ``updateTree(s, tree, mid ``+` `1``, end,``                  ``(``2` `*` `treeNode) ``+` `1``, idx, X)` `    ``# Update the current node``    ``tree[treeNode].square_sum ``=` `(tree[(``2` `*` `treeNode)].square_sum ``+``                                 ``tree[(``2` `*` `treeNode) ``+` `1``].square_sum)` `# Function to perform the given queries``def` `PerformQuery(S, Q):``    ` `    ``n ``=` `len``(S)` `    ``# Stores the segment tree``    ``tree ``=` `[treeNode(``0``) ``for` `i ``in` `range``((``4` `*` `n) ``+` `1``)]` `    ``# Traverse the segment tree``    ``for` `i ``in` `range``(``4` `*` `n ``+` `1``):``        ` `        ``# Assign 0 to each node``        ``tree[i].square_sum ``=` `0` `    ``# Builds segment tree``    ``buildTree(S, tree, ``0``, n ``-` `1``, ``1``)` `    ``# Traverse the query array Q[][]``    ``for` `i ``in` `range``(``len``(Q)):``        ` `        ``# If query is of type S``        ``if` `(Q[i][``0``] ``=``=` `"S"``):``            ` `            ``# Stores the left boundary``            ``L ``=` `int``(Q[i][``1``])` `            ``# Stores the right boundary``            ``R ``=` `int``(Q[i][``2``])` `            ``# Prints the sum of squares of the``            ``# alphabetic positions of the characters``            ``print``(querySquareSum(tree, ``0``, n ``-` `1``,``                                 ``1``, L, R))` `        ``# Otherwise``        ``elif` `(Q[i][``0``] ``=``=` `"U"``):` `            ``# Stores the index of the``            ``# character to be updated``            ``I ``=` `int``(Q[i][``1``])` `            ``# Update the segment tree``            ``updateTree(S, tree, ``0``, n ``-` `1``,``                       ``1``, I, Q[i][``2``][``0``])` `# Driver Code``if` `__name__ ``=``=` `'__main__'``:``    ` `    ``# Input``    ``S ``=` `"geeksforgeeks"``    ``Q ``=` `[ [ ``"S"``, ``"0"``, ``"2"` `],``          ``[ ``"S"``, ``"1"``, ``"2"` `],``          ``[ ``"U"``, ``"1"``, ``"a"` `],``          ``[ ``"S"``, ``"0"``, ``"2"` `],``          ``[ ``"S"``, ``"4"``, ``"5"` `] ]``          ` `    ``# Function call``    ``PerformQuery([i ``for` `i ``in` `S], Q)` `# This code is contributed by mohit kumar 29`
Output:
```99
50
75
397```

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

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 industry experts, please refer Geeks Classes Live

My Personal Notes arrow_drop_up