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[1] 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 = 397Input: 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++ implementation of // the above approach #include <bits/stdc++.h> 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<vector<string> > 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][0] == "S" ) {
// Stores the left boundary
int L = stoi(Q[i][1]);
// Stores the right boundary
int R = stoi(Q[i][2]);
// 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][0] == "U" ) {
// Stores the index of the
// character to be updated
int I = stoi(Q[i][1]);
// Update the segment tree
updateTree(S, tree, 0, n - 1,
1, I, Q[i][2][0]);
}
}
} // Driver Code int main()
{ // Input
string S = "geeksforgeeks" ;
vector<vector<string> > Q = { { "S" , "0" , "2" },
{ "S" , "1" , "2" },
{ "U" , "1" , "a" },
{ "S" , "0" , "2" },
{ "S" , "4" , "5" } };
// Function call
PerformQuery(S, Q);
} |
// 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 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 |
using System;
public class treeNode
{ public int square_sum;
public treeNode( int square_sum)
{
this .square_sum = square_sum;
}
}; public class GFG{
// 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.GetLength(0); i++)
{
// If query is of type S
if (Q[i,0] == "S" )
{
// Stores the left boundary
int L = Int32.Parse(Q[i,1]);
// Stores the right boundary
int R = Int32.Parse(Q[i,2]);
// Prints the sum of squares of the
// alphabetic positions of the characters
Console.WriteLine(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 = Int32.Parse(Q[i,1]);
// Update the segment tree
updateTree(s, tree, 0, n - 1, 1, I,
Q[i,2][0]);
}
}
} // Driver Code static public void Main (){
// 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 unknown2108. |
<script> // Javascript implementation of // the above approach // Structure of a node // of a Segment Tree class treeNode { constructor( square_sum)
{
this .square_sum = square_sum;
}
} // Function to construct the Segment Tree function buildTree(s,tree,start,end,treenode)
{ // If start and end are equal
if (start == end)
{
// Assign squares of positions
// of the characters
tree[treenode].square_sum = Math.pow(
s[start].charCodeAt(0) - 'a' .charCodeAt(0) + 1, 2);
return ;
}
// Stores the mid value of
// the range [start, end]
let mid = start + Math.floor((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 function querySquareSum(tree,start,end,treenode,l,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]
let mid = start + Math.floor((end - start) / 2);
// Function call to left subtree
let X = querySquareSum(tree, start, mid,
2 * treenode, l, r);
// Function call to right subtree
let 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 function updateTree(s,tree,start,end,treenode,idx,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 = Math.pow(
X.charCodeAt(0) - 'a' .charCodeAt(0) + 1, 2);
return ;
}
// Calculate middle of the range [start, end]
let mid = start + Math.floor((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 function PerformQuery(S,Q)
{ let n = S.length;
// Stores the segment tree
let tree = new Array((4 * n) + 1);
// Traverse the segment tree
for (let i = 0; i <= (4 * n); i = i + 1)
{
// Assign 0 to each node
tree[i] = new treeNode(0);
}
let s = S.split( "" );
// Builds segment tree
buildTree(s, tree, 0, n - 1, 1);
// Traverse the query array Q[][]
for (let i = 0; i < Q.length; i++)
{
// If query is of type S
if (Q[i][0] == "S" )
{
// Stores the left boundary
let L = parseInt(Q[i][1]);
// Stores the right boundary
let R = parseInt(Q[i][2]);
// Prints the sum of squares of the
// alphabetic positions of the characters
document.write(querySquareSum(
tree, 0, n - 1, 1, L, R)+ "<br>" );
}
// Otherwise
else if (Q[i][0] == "U" )
{
// Stores the index of the
// character to be updated
let I = parseInt(Q[i][1]);
// Update the segment tree
updateTree(s, tree, 0, n - 1, 1, I,
Q[i][2][0]);
}
}
} // Driver Code let S = "geeksforgeeks" ;
let 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 patel2127 </script> |
99 50 75 397
Time Complexity: O((N + M) * log N)
Auxiliary Space: O(N)