给定长度为N的字符串S,以及以下类型的M个查询:
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.
例子:
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.
天真的方法:
查询类型1:我们将计算查询字符串中每个字符在[L…R]范围内的频率,然后将所有计算出的频率相乘以获得所需的结果。
查询类型2:我们将字符串的第i个字符替换为给定字符。
时间复杂度: 0(m * n)
高效的方法:
- 使用细分树,我们可以在log(n)时间内执行这两项操作。段树的每个节点都将包含[L..R]范围内的字符频率。
- 函数构建需要n * log(n)时间来创建一个段树,每个节点都包含字符串某个段的字符频率。
- 函数get返回一个包含所有字符频率的向量。给定查询字符串的所有频率乘以1e9 + 7模得到所需的结果。
- 该函数更新减少了放置在前面的字符的频率,并使出现在段树的节点中的新字符的频率增加了一个。
- 函数add_two_result将两个向量相加并返回其结果。
以下是上述方法的C++实现:
CPP
// C++ implementation of the approach
#include
using namespace std;
#define N 400005
#define mod 1000000007
vector 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 add_two_result(vector v1,
vector v2)
{
vector 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 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 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 v1 = get(2 * pos, l,
r, st, mid);
//storing answer of left child n v1
vector 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 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 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[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);
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
时间复杂度: 0(m * log(n)+ n * log(n))