結果

問題 No.3667 Prefix Count Queries
ユーザー Rino-program
提出日時 2026-08-30 20:49:58
言語 C++23(gcc16)
(gcc 16.1.0 + boost 1.92.0)
コンパイル:
g++-16 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
AC  
実行時間 52 ms / 2,000 ms
+ 588µs
コード長 2,694 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 1,675 ms
コンパイル使用メモリ 209,452 KB
実行使用メモリ 10,496 KB
最終ジャッジ日時 2026-09-01 00:51:29
合計ジャッジ時間 5,026 ms
ジャッジサーバーID
(参考情報)
judge1_0 / judge2_0
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 5
other AC * 35
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#pragma GCC optimize("O3,unroll-loops")

using namespace std;

int main() {
    // 高速入出力設定
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N;
    if (!(cin >> N)) return 0;

    vector<string> A(N);
    for (int i = 0; i < N; ++i) {
        cin >> A[i];
    }

    // 1. 辞書順にソート
    sort(A.begin(), A.end());

    int Q;
    cin >> Q;

    // 区間 [L, R) を管理するスタック (初期状態: 空文字列 -> [0, N))
    vector<pair<int, int>> history;
    history.emplace_back(0, N);

    // インデックス idx の文字列の d 文字目を返す関数(長さが足りない場合は -1)
    auto get_char = [&](int idx, int d) -> int {
        if (d >= (int)A[idx].size()) return -1;
        return static_cast<unsigned char>(A[idx][d]);
    };

    while (Q--) {
        int type;
        cin >> type;

        if (type == 1) {
            char x;
            cin >> x;
            auto [L, R] = history.back();
            int d = (int)history.size() - 1; // 現在追加しようとしている文字の深さ (0-indexed)

            if (L >= R) {
                // すでに一致するものが存在しない場合は空区間を維持
                history.emplace_back(0, 0);
            } else {
                int target = static_cast<unsigned char>(x);

                // lower_bound: A[mid] の d 文字目が >= target となる最初の位置
                int l1 = L, r1 = R;
                while (l1 < r1) {
                    int mid = l1 + (r1 - l1) / 2;
                    if (get_char(mid, d) >= target) {
                        r1 = mid;
                    } else {
                        l1 = mid + 1;
                    }
                }
                int new_L = l1;

                // upper_bound: A[mid] の d 文字目が > target となる最初の位置
                int l2 = new_L, r2 = R;
                while (l2 < r2) {
                    int mid = l2 + (r2 - l2) / 2;
                    if (get_char(mid, d) > target) {
                        r2 = mid;
                    } else {
                        l2 = mid + 1;
                    }
                }
                int new_R = l2;

                history.emplace_back(new_L, new_R);
            }
        } else if (type == 2) {
            // 末尾削除: 1つ前の状態に巻き戻す
            history.pop_back();
        } else if (type == 3) {
            // 現在の区間に含まれる文字列数を出力
            auto [L, R] = history.back();
            cout << (R - L) << "\n";
        }
    }

    return 0;
}
0