結果
問題 | No.2020 Sum of Common Prefix Length |
ユーザー | Forested |
提出日時 | 2022-07-22 22:30:08 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 205 ms / 2,000 ms |
コード長 | 14,832 bytes |
コンパイル時間 | 2,229 ms |
コンパイル使用メモリ | 153,812 KB |
実行使用メモリ | 80,092 KB |
最終ジャッジ日時 | 2024-07-04 07:01:45 |
合計ジャッジ時間 | 7,876 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
6,816 KB |
testcase_01 | AC | 2 ms
6,944 KB |
testcase_02 | AC | 2 ms
6,940 KB |
testcase_03 | AC | 3 ms
6,944 KB |
testcase_04 | AC | 3 ms
6,940 KB |
testcase_05 | AC | 3 ms
6,940 KB |
testcase_06 | AC | 3 ms
6,940 KB |
testcase_07 | AC | 57 ms
6,948 KB |
testcase_08 | AC | 55 ms
6,940 KB |
testcase_09 | AC | 56 ms
6,940 KB |
testcase_10 | AC | 57 ms
6,944 KB |
testcase_11 | AC | 59 ms
6,948 KB |
testcase_12 | AC | 58 ms
6,944 KB |
testcase_13 | AC | 57 ms
6,940 KB |
testcase_14 | AC | 61 ms
6,940 KB |
testcase_15 | AC | 70 ms
13,256 KB |
testcase_16 | AC | 67 ms
13,332 KB |
testcase_17 | AC | 122 ms
31,600 KB |
testcase_18 | AC | 106 ms
24,236 KB |
testcase_19 | AC | 111 ms
26,716 KB |
testcase_20 | AC | 177 ms
66,032 KB |
testcase_21 | AC | 205 ms
62,464 KB |
testcase_22 | AC | 190 ms
57,156 KB |
testcase_23 | AC | 185 ms
56,380 KB |
testcase_24 | AC | 198 ms
63,260 KB |
testcase_25 | AC | 196 ms
64,116 KB |
testcase_26 | AC | 115 ms
52,808 KB |
testcase_27 | AC | 2 ms
6,940 KB |
testcase_28 | AC | 61 ms
8,956 KB |
testcase_29 | AC | 62 ms
9,216 KB |
testcase_30 | AC | 62 ms
8,828 KB |
testcase_31 | AC | 159 ms
70,000 KB |
testcase_32 | AC | 167 ms
80,092 KB |
testcase_33 | AC | 119 ms
52,804 KB |
testcase_34 | AC | 84 ms
23,908 KB |
testcase_35 | AC | 84 ms
24,732 KB |
testcase_36 | AC | 122 ms
48,552 KB |
testcase_37 | AC | 102 ms
33,224 KB |
ソースコード
#ifndef LOCAL #define FAST_IO #endif // ===== template.hpp ===== #include <algorithm> #include <array> #include <bitset> #include <cassert> #include <cmath> #include <iomanip> #include <iostream> #include <list> #include <map> #include <numeric> #include <queue> #include <random> #include <set> #include <stack> #include <string> #include <tuple> #include <unordered_map> #include <unordered_set> #include <utility> #include <vector> #define OVERRIDE(a, b, c, d, ...) d #define REP2(i, n) for (i32 i = 0; i < (i32) (n); ++i) #define REP3(i, m, n) for (i32 i = (i32) (m); i < (i32) (n); ++i) #define REP(...) OVERRIDE(__VA_ARGS__, REP3, REP2)(__VA_ARGS__) #define PER(i, n) for (i32 i = (i32) (n) - 1; i >= 0; --i) #define ALL(x) begin(x), end(x) using namespace std; using u32 = unsigned int; using u64 = unsigned long long; using u128 = __uint128_t; using i32 = signed int; using i64 = signed long long; using i128 = __int128_t; using f64 = double; using f80 = long double; template <typename T> using Vec = vector<T>; template <typename T> bool chmin(T &x, const T &y) { if (x > y) { x = y; return true; } return false; } template <typename T> bool chmax(T &x, const T &y) { if (x < y) { x = y; return true; } return false; } istream &operator>>(istream &is, i128 &x) { i64 v; is >> v; x = v; return is; } ostream &operator<<(ostream &os, i128 x) { os << (i64) x; return os; } istream &operator>>(istream &is, u128 &x) { u64 v; is >> v; x = v; return is; } ostream &operator<<(ostream &os, u128 x) { os << (u64) x; return os; } [[maybe_unused]] constexpr i32 INF = 1000000100; [[maybe_unused]] constexpr i64 INF64 = 3000000000000000100; struct SetUpIO { SetUpIO() { #ifdef FAST_IO ios::sync_with_stdio(false); cin.tie(nullptr); #endif cout << fixed << setprecision(15); } } set_up_io; // ===== template.hpp ===== #ifdef DEBUGF #include "cpl/template/debug.hpp" #else #define DBG(x) (void) 0 #endif // ===== trie.hpp ===== #include <algorithm> #include <array> #include <string> #include <vector> class Trie { std::vector<std::array<int, 26>> trie; std::vector<int> cnt; public: static constexpr int none = -1; private: int make_node() { int s = trie.size(); trie.emplace_back(std::array<int, 26>()); std::fill(trie[s].begin(), trie[s].end(), none); cnt.push_back(0); return s; } public: Trie() : trie(), cnt() { make_node(); } int size() const { return (int) trie.size(); } const std::array<int, 26> &operator[](int i) const { return trie[i]; } int insert(const std::string &s) { int cur = 0; for (char c : s) { if (trie[cur][c - 'a'] == none) { trie[cur][c - 'a'] = make_node(); } cur = trie[cur][c - 'a']; } return cnt[cur]++; } int find(const std::string &s) const { int cur = 0; for (char c : s) { int nxt = trie[cur][c - 'a']; if (nxt == none) { return none; } cur = nxt; } return cur; } int count(const std::string &s) const { int node = find(s); if (node == none) { return 0; } else { return cnt[node]; } } int cnt_node(int i) const { return cnt[i]; } }; // ===== trie.hpp ===== // ===== graph.hpp ===== #include <utility> #include <vector> #include <numeric> #include <cassert> template <typename Edge> class Graph { std::vector<std::vector<Edge>> edges; public: Graph() : edges() {} Graph(int v) : edges(v) { assert(v >= 0); } std::vector<int> add_vertices(int n) { int v = (int) edges.size(); std::vector<int> idx(n); std::iota(idx.begin(), idx.end(), v); edges.resize(edges.size() + n); return idx; } template <typename... T> void add_directed_edge(int from, int to, T &&...val) { assert(from >= 0 && from < (int) edges.size()); assert(to >= 0 && to < (int) edges.size()); edges[from].emplace_back(Edge(to, std::forward<T>(val)...)); } template <typename... T> void add_undirected_edge(int u, int v, const T &...val) { assert(u >= 0 && u < (int) edges.size()); assert(v >= 0 && v < (int) edges.size()); edges[u].emplace_back(Edge(v, val...)); edges[v].emplace_back(Edge(u, val...)); } int size() const { return (int) edges.size(); } const std::vector<Edge> &operator[](int v) const { assert(v >= 0 && v < (int) edges.size()); return edges[v]; } std::vector<Edge> &operator[](int v) { assert(v >= 0 && v < (int) edges.size()); return edges[v]; } }; struct UnweightedEdge { int to; UnweightedEdge(int t) : to(t) {} explicit operator int() const { return to; } using Weight = std::size_t; Weight weight() const { return 1; } }; template <typename T> struct WeightedEdge { int to; T wt; WeightedEdge(int t, const T &w) : to(t), wt(w) {} explicit operator int() const { return to; } using Weight = T; Weight weight() const { return wt; } }; // ===== graph.hpp ===== // ===== heavy_light_decomposition.hpp ===== #include <algorithm> #include <cassert> #include <utility> #include <vector> class HeavyLightDecomposition { std::vector<int> siz; std::vector<int> par; std::vector<int> hea; std::vector<int> in; std::vector<int> out; std::vector<int> dep; std::vector<int> rev; template <typename G> void dfs1(G &g, int v) { if (!g[v].empty() && (int) g[v][0] == par[v]) { std::swap(g[v][0], g[v].back()); } for (auto &e : g[v]) { int u = (int)e; if (u != par[v]) { par[u] = v; dfs1(g, u); siz[v] += siz[u]; if (siz[u] > siz[g[v][0]]) { std::swap(g[v][0], e); } } } } template <typename G> void dfs2(const G &g, int v, int &time) { in[v] = time; rev[time++] = v; for (auto &e : g[v]) { int u = (int)e; if (u == par[v]) { continue; } if (u == (int) g[v][0]) { hea[u] = hea[v]; } else { hea[u] = u; } dep[u] = dep[v] + 1; dfs2(g, u, time); } out[v] = time; } public: template <typename G> HeavyLightDecomposition(G &g, int root = 0) : siz(g.size(), 1), par(g.size(), root), hea(g.size(), root), in(g.size(), 0), out(g.size(), 0), dep(g.size(), 0), rev(g.size(), 0) { assert(root >= 0 && root < static_cast<int>(g.size())); dfs1(g, root); int time = 0; dfs2(g, root, time); } int subtree_size(int v) const { assert(v >= 0 && v < static_cast<int>(siz.size())); return siz[v]; } int parent(int v) const { assert(v >= 0 && v < static_cast<int>(par.size())); return par[v]; } int in_time(int v) const { assert(v >= 0 && v < static_cast<int>(in.size())); return in[v]; } int out_time(int v) const { assert(v >= 0 && v < static_cast<int>(out.size())); return out[v]; } int depth(int v) const { assert(v >= 0 && v < static_cast<int>(dep.size())); return dep[v]; } int time_to_vertex(int t) const { assert(t >= 0 && t < static_cast<int>(rev.size())); return rev[t]; } int la(int v, int k) const { assert(v >= 0 && v < static_cast<int>(dep.size())); assert(k >= 0); while (true) { int u = hea[v]; if (in[u] + k <= in[v]) { return rev[in[v] - k]; } k -= in[v] - in[u] + 1; v = par[u]; } return 0; } int forward(int v, int dst) const { assert(v >= 0 && v < static_cast<int>(dep.size())); assert(dst >= 0 && dst < static_cast<int>(dep.size())); assert(v != dst); int l = lca(v, dst); if (l == v) { return la(dst, dist(v, dst) - 1); } else { return par[v]; } } int lca(int u, int v) const { assert(u >= 0 && u < static_cast<int>(dep.size())); assert(v >= 0 && v < static_cast<int>(dep.size())); while (u != v) { if (in[u] > in[v]) { std::swap(u, v); } if (hea[u] == hea[v]) { v = u; } else { v = par[hea[v]]; } } return u; } int dist(int u, int v) const { assert(u >= 0 && u < static_cast<int>(dep.size())); assert(v >= 0 && v < static_cast<int>(dep.size())); return dep[u] + dep[v] - 2 * dep[lca(u, v)]; } std::vector<std::pair<int, int>> path(int u, int v, bool edge) const { assert(u >= 0 && u < static_cast<int>(dep.size())); assert(v >= 0 && v < static_cast<int>(dep.size())); std::vector<std::pair<int, int>> fromu, fromv; bool rev = false; while (true) { if (u == v && edge) { break; } if (in[u] > in[v]) { std::swap(u, v); std::swap(fromu, fromv); rev ^= true; } if (hea[u] == hea[v]) { fromv.emplace_back(in[v], in[u] + (int)edge); v = u; break; } else { fromv.emplace_back(in[v], in[hea[v]]); v = par[hea[v]]; } } if (rev) { std::swap(fromu, fromv); } std::reverse(fromv.begin(), fromv.end()); fromu.reserve(fromv.size()); for (auto [x, y] : fromv) { fromu.emplace_back(y, x); } return fromu; } }; // ===== heavy_light_decomposition.hpp ===== // ===== fenwick_tree.hpp ===== #include <cassert> #include <vector> // ===== operations.hpp ===== #include <limits> #include <utility> template <typename T> struct Add { using Value = T; static Value id() { return T(0); } static Value op(const Value &lhs, const Value &rhs) { return lhs + rhs; } static Value inv(const Value &x) { return -x; } }; template <typename T> struct Mul { using Value = T; static Value id() { return Value(1); } static Value op(const Value &lhs, const Value &rhs) { return lhs * rhs; } static Value inv(const Value &x) { return Value(1) / x; } }; template <typename T> struct Min { using Value = T; static Value id() { return std::numeric_limits<T>::max(); } static Value op(const Value &lhs, const Value &rhs) { return std::min(lhs, rhs); } }; template <typename T> struct Max { using Value = T; static Value id() { return std::numeric_limits<Value>::min(); } static Value op(const Value &lhs, const Value &rhs) { return std::max(lhs, rhs); } }; template <typename T> struct Xor { using Value = T; static Value id() { return T(0); } static Value op(const Value &lhs, const Value &rhs) { return lhs ^ rhs; } static Value inv(const Value &x) { return x; } }; template <typename Monoid> struct Reversible { using Value = std::pair<typename Monoid::Value, typename Monoid::Value>; static Value id() { return Value(Monoid::id(), Monoid::id()); } static Value op(const Value &v1, const Value &v2) { return Value( Monoid::op(v1.first, v2.first), Monoid::op(v2.second, v1.second)); } }; // ===== operations.hpp ===== template <typename CommutativeGroup> class FenwickTree { public: using Value = typename CommutativeGroup::Value; private: std::vector<Value> data; public: FenwickTree(int n) : data(n, CommutativeGroup::id()) {} void add(int idx, const Value &x) { assert(idx >= 0 && idx < static_cast<int>(data.size())); for (; idx < static_cast<int>(data.size()); idx |= idx + 1) { data[idx] = CommutativeGroup::op(data[idx], x); } } Value sum(int r) const { assert(r >= 0 && r <= static_cast<int>(data.size())); Value ret = CommutativeGroup::id(); for (; r > 0; r &= r - 1) { ret = CommutativeGroup::op(ret, data[r - 1]); } return ret; } Value sum(int l, int r) const { assert(l >= 0 && l <= r && r <= static_cast<int>(data.size())); return CommutativeGroup::op(sum(r), CommutativeGroup::inv(sum(l))); } }; // ===== fenwick_tree.hpp ===== int main() { i32 n; cin >> n; Vec<string> s(n); REP(i, n) { cin >> s[i]; } i32 q; cin >> q; Vec<tuple<i32, i32, char>> queries(q); for (auto &[t, x, c] : queries) { cin >> t; --t; if (t == 0) { cin >> x >> c; --x; } else { cin >> x; --x; c = '$'; } } Vec<i32> init_len(n); REP(i, n) { init_len[i] = (i32) s[i].size(); } for (auto [t, x, c] : queries) { if (t == 0) { s[x].push_back(c); } } Trie trie; REP(i, n) { trie.insert(s[i]); } Graph<i32> tree(trie.size()); REP(i, trie.size()) { for (i32 to : trie[i]) { if (to != Trie::none) { tree.add_undirected_edge(i, to); } } } HeavyLightDecomposition hld(tree); FenwickTree<Add<i64>> fw(tree.size()); Vec<i32> pos(n); REP(i, n) { i32 cur = 0; REP(j, init_len[i]) { cur = trie[cur][s[i][j] - 'a']; fw.add(hld.in_time(cur), 1); } pos[i] = cur; } DBG(pos); for (auto [t, x, c] : queries) { if (t == 0) { pos[x] = trie[pos[x]][c - 'a']; DBG(pos[x]); fw.add(hld.in_time(pos[x]), 1); } else { i64 ans = 0; for (auto [x, y] : hld.path(0, pos[x], false)) { if (x > y) { swap(x, y); } ans += fw.sum(x, y + 1); } cout << ans << '\n'; } } }