#![allow(non_snake_case, unused_imports)] use proconio::{fastout, input, marker::*}; #[fastout] fn main() { input! { N: usize, L: usize, Q: usize, mut S: [Chars; N], } let mut rhs = vec![]; for i in 0..N { let rh = UpdateableRollingHash::from(&S[i]); rhs.push(rh); } for _ in 0..Q { input! { t: usize } if t == 1 { input! { k: Usize1, c: char, d: char, } for i in 0..N { if S[i][k] == c { S[i][k] = d; rhs[i].update(k, d); } } } else { input! { t: Chars, } let l = t.len(); let rh = UpdateableRollingHash::from(&t); let h = rh.hash(0..l); let mut ans = 0usize; for i in 0..N { let hi = rhs[i].hash(0..l); if hi == h { ans += 1; } } println!("{}", ans); } } } pub struct UpdateableRollingHash { length: usize, tree: Vec, pow: Vec, } impl UpdateableRollingHash { const MOD: u64 = (1_u64 << 61) - 1; const MASK_30: u64 = (1_u64 << 30) - 1; const MASK_31: u64 = (1_u64 << 31) - 1; const MASK_61: u64 = (1_u64 << 61) - 1; const BASE: u64 = 100; const STR_BASE: char = 'a'; fn inv(x: u64) -> u64 { return Self::pow(x, Self::MOD - 2); } fn pow(mut a: u64, mut b: u64) -> u64 { let mut ret = 1; while b > 0 { if b & 1 == 1 { ret = Self::cmod(Self::mul(ret, a)); } a = Self::cmod(Self::mul(a, a)); b >>= 1; } return ret; } fn mul(a: u64, b: u64) -> u64 { let au = a >> 31; let ad = a & Self::MASK_31; let bu = b >> 31; let bd = b & Self::MASK_31; let mid = ad * bu + au * bd; let midu = mid >> 30; let midd = mid & Self::MASK_30; return Self::cmod(au * bu * 2 + midu + (midd << 31) + ad * bd); } fn cmod(x: u64) -> u64 { let xu = x >> 61; let xd = x & Self::MASK_61; let ret = xu + xd; if ret >= Self::MOD { return ret - Self::MOD; } else { return ret; } } /// Prepare to calc given string s's substring hash value pub fn from(s: &[char]) -> Self { let length = s.len(); let mut tree = vec![0; 2 * length]; let mut pow = vec![1]; for i in 0..length { pow.push(Self::cmod(Self::mul(pow[i], Self::BASE))); } for i in 0..length { tree[i + length] = Self::cmod(Self::mul( s[i] as u64 + 1 - Self::STR_BASE as u64, pow[length - i - 1], )); } for i in (1..length).rev() { tree[i] = Self::cmod(tree[i << 1] + tree[(i << 1) | 1]); } return Self { length: length, tree: tree, pow: pow, }; } /// Update p-th character to 'c' pub fn update(&mut self, mut p: usize, c: char) { let v = Self::cmod(Self::mul( c as u64 + 1 - Self::STR_BASE as u64, self.pow[self.length - p - 1], )); p += self.length; self.tree[p] = v; while p > 1 { p >>= 1; self.tree[p] = Self::cmod(self.tree[p << 1] + self.tree[(p << 1) | 1]); } } fn _get_sum(&self, left: usize, right: usize) -> u64 { let (mut l, mut r) = (left + self.length, right + self.length); let (mut vl, mut vr) = (0, 0); while l < r { if l & 1 == 1 { vl = Self::cmod(vl + self.tree[l]); l += 1; } if r & 1 == 1 { r -= 1; vr = Self::cmod(self.tree[r] + vr); } l >>= 1; r >>= 1; } return Self::cmod(vl + vr); } fn _hash(&self, left: usize, right: usize) -> u64 { let lv = self._get_sum(0, left); let rv = self._get_sum(0, right); return Self::cmod(Self::mul( rv + Self::MOD * 4 - lv, Self::inv(self.pow[self.length - right + 1]), )); } /// Calculate hash value of s[range] pub fn hash>(&self, range: R) -> u64 { let left = match range.start_bound() { std::ops::Bound::Included(&l) => l, std::ops::Bound::Excluded(&l) => l + 1, std::ops::Bound::Unbounded => 0, }; let right = match range.end_bound() { std::ops::Bound::Included(&r) => r + 1, std::ops::Bound::Excluded(&r) => r, std::ops::Bound::Unbounded => self.length - 1, }; return self._hash(left, right); } }