use proconio::{input, marker::{Usize1, Chars}}; use std::collections::*; fn main() { input! { N: usize, L: usize, Q: usize, S: [Chars; N], } let mut trie = Trie::new(L); for s in &S { trie.add(&lower_alphabets_to_usizes(&s), 1); } for _ in 0 .. Q { input!(qtype: usize); match qtype { 1 => { input!(k: Usize1, c: char, d: char); let c = la2i(c); let d = la2i(d); trie.substitute(k, c, d); } 2 => { input!(t: Chars); let t = lower_alphabets_to_usizes(&t); println!("{}", trie.search(&t)); } _ => unreachable!() } } } fn la2i(c: char) -> usize { (c as u8 - b'a') as usize } fn lower_alphabets_to_usizes(chars: &[char]) -> Vec { chars.iter().map(|&c| la2i(c) ).collect() } struct Trie { nodes: Vec, by_index_key: Vec>>, } impl Trie { pub fn new(l: usize) -> Self { Self { nodes: vec![TrieNode::new()], by_index_key: vec![vec![vec![]; 26]; l], } } pub fn add(&mut self, s: &[usize], add: i64) { let mut current = 0; self.nodes[current].sum += add; for i in 0 .. s.len() { let c = s[i]; if self.nodes[current].children[c].is_none() { let id = self.nodes.len(); let mut node = TrieNode::new(); node.parent = Some(current); self.nodes.push(node); self.nodes[current].children[c] = Some(id); self.by_index_key[i][c].push(id); } current = self.nodes[current].children[c].unwrap(); self.nodes[current].sum += add; } } pub fn substitute(&mut self, k: usize, from: usize, to: usize) { let src = std::mem::take(&mut self.by_index_key[k][from]); let mut merge_stack = vec![]; for &id in &src { if self.nodes[id].is_removed { continue; } let Some(parent) = self.nodes[id].parent else { continue }; if let Some(merged) = self.nodes[parent].children[to] { self.nodes[id].is_removed = true; merge_stack.push((id, merged, k)); } else { self.nodes[parent].children[to] = Some(id); self.by_index_key[k][to].push(id); self.nodes[id].parent = Some(parent); } self.nodes[parent].children[from] = None; } while let Some((src, dst, k)) = merge_stack.pop() { self.nodes[dst].sum += self.nodes[src].sum; for c in 0 .. 26 { if let Some(src_child) = self.nodes[src].children[c] { if let Some(dst_child) = self.nodes[dst].children[c] { self.nodes[src_child].is_removed = true; merge_stack.push((src_child, dst_child, k + 1)); } else { self.nodes[dst].children[c] = Some(src_child); self.nodes[src_child].parent = Some(dst); } } } } } pub fn search(&self, s: &[usize]) -> i64 { let mut cur = 0; for i in 0 .. s.len() { let c = s[i]; if let Some(child) = self.nodes[cur].children[c] { cur = child; } else { return 0; } } self.nodes[cur].sum } } struct TrieNode { pub is_removed: bool, pub parent: Option, pub sum: i64, pub children: Vec>, } impl TrieNode { pub fn new() -> Self { Self { is_removed: false, parent: None, sum: 0, children: vec![None; 26], } } }