結果

問題 No.2761 Substitute and Search
ユーザー maguroflymagurofly
提出日時 2024-04-29 22:44:27
言語 Rust
(1.77.0)
結果
WA  
実行時間 -
コード長 4,049 bytes
コンパイル時間 13,877 ms
コンパイル使用メモリ 390,748 KB
実行使用メモリ 809,156 KB
最終ジャッジ日時 2024-05-07 04:51:32
合計ジャッジ時間 17,095 ms
ジャッジサーバーID
(参考情報)
judge3 / judge1
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 WA -
testcase_01 AC 1 ms
6,816 KB
testcase_02 WA -
testcase_03 AC 1 ms
6,940 KB
testcase_04 AC 245 ms
32,272 KB
testcase_05 AC 66 ms
20,736 KB
testcase_06 MLE -
testcase_07 -- -
testcase_08 -- -
testcase_09 -- -
testcase_10 -- -
testcase_11 -- -
testcase_12 -- -
testcase_13 -- -
testcase_14 -- -
testcase_15 -- -
権限があれば一括ダウンロードができます
コンパイルメッセージ
warning: unused import: `std::collections::*`
 --> src/main.rs:2:5
  |
2 | use std::collections::*;
  |     ^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: variable `N` should have a snake case name
 --> src/main.rs:6:9
  |
6 |         N: usize, L: usize, Q: usize,
  |         ^ help: convert the identifier to snake case: `n`
  |
  = note: `#[warn(non_snake_case)]` on by default

warning: variable `L` should have a snake case name
 --> src/main.rs:6:19
  |
6 |         N: usize, L: usize, Q: usize,
  |                   ^ help: convert the identifier to snake case: `l`

warning: variable `Q` should have a snake case name
 --> src/main.rs:6:29
  |
6 |         N: usize, L: usize, Q: usize,
  |                             ^ help: convert the identifier to snake case: `q`

warning: variable `S` should have a snake case name
 --> src/main.rs:7:9
  |
7 |         S: [Chars; N],
  |         ^ help: convert the identifier to snake case (notice the capitalization): `s`

ソースコード

diff #

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<usize> {
    chars.iter().map(|&c| la2i(c) ).collect()
}

struct Trie {
    nodes: Vec<TrieNode>,
    by_index_key: Vec<Vec<Vec<usize>>>,
}
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() {
            if self.nodes[src].is_removed {
                continue;
            }
            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<usize>,
    pub sum: i64,
    pub children: Vec<Option<usize>>,
}
impl TrieNode {
    pub fn new() -> Self {
        Self {
            is_removed: false,
            parent: None,
            sum: 0,
            children: vec![None; 26],
        }
    }
}
0