結果
問題 | No.2340 Triple Tree Query (Easy) |
ユーザー | risujiroh |
提出日時 | 2023-06-02 23:05:33 |
言語 | C++23 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 304 ms / 5,000 ms |
コード長 | 10,782 bytes |
コンパイル時間 | 4,373 ms |
コンパイル使用メモリ | 296,096 KB |
実行使用メモリ | 26,804 KB |
最終ジャッジ日時 | 2024-06-09 01:06:47 |
合計ジャッジ時間 | 15,194 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
5,248 KB |
testcase_01 | AC | 8 ms
5,248 KB |
testcase_02 | AC | 7 ms
5,376 KB |
testcase_03 | AC | 7 ms
5,376 KB |
testcase_04 | AC | 7 ms
5,376 KB |
testcase_05 | AC | 13 ms
5,376 KB |
testcase_06 | AC | 259 ms
19,736 KB |
testcase_07 | AC | 257 ms
19,740 KB |
testcase_08 | AC | 249 ms
19,736 KB |
testcase_09 | AC | 257 ms
19,740 KB |
testcase_10 | AC | 241 ms
19,744 KB |
testcase_11 | AC | 244 ms
19,736 KB |
testcase_12 | AC | 261 ms
19,740 KB |
testcase_13 | AC | 262 ms
19,744 KB |
testcase_14 | AC | 272 ms
19,744 KB |
testcase_15 | AC | 253 ms
19,736 KB |
testcase_16 | AC | 302 ms
26,804 KB |
testcase_17 | AC | 289 ms
24,364 KB |
testcase_18 | AC | 301 ms
23,980 KB |
testcase_19 | AC | 298 ms
26,160 KB |
testcase_20 | AC | 303 ms
23,736 KB |
testcase_21 | AC | 211 ms
19,956 KB |
testcase_22 | AC | 209 ms
19,952 KB |
testcase_23 | AC | 213 ms
19,824 KB |
testcase_24 | AC | 304 ms
19,508 KB |
testcase_25 | AC | 280 ms
19,376 KB |
testcase_26 | AC | 293 ms
19,376 KB |
testcase_27 | AC | 269 ms
19,380 KB |
testcase_28 | AC | 279 ms
19,368 KB |
testcase_29 | AC | 210 ms
19,960 KB |
testcase_30 | AC | 210 ms
19,960 KB |
testcase_31 | AC | 211 ms
19,824 KB |
testcase_32 | AC | 255 ms
19,824 KB |
testcase_33 | AC | 264 ms
19,844 KB |
testcase_34 | AC | 251 ms
19,852 KB |
testcase_35 | AC | 263 ms
19,860 KB |
testcase_36 | AC | 239 ms
19,848 KB |
ソースコード
#if __INCLUDE_LEVEL__ == 0 #include <bits/stdc++.h> using namespace std; #undef assert #define assert(expr) (expr) || (__builtin_unreachable(), 0) #include __BASE_FILE__ #define ALL(f, r, ...) \ [&](auto&& _) { return f(begin(_), end(_), ##__VA_ARGS__); }(r) namespace std::ranges::views { namespace { using Fp = atcoder::modint998244353; Fp op(Fp x, Fp y) { return x + y; } Fp e() { return 0; } struct F { Fp c; Fp d; }; Fp mapping(F f, Fp x) { return x * f.c + f.d; } F composition(F g, F f) { return {f.c * g.c, f.d * g.c + g.d}; } F id() { return {1, 0}; } void solve() { int n, q; cin >> tie(n, q); HldTree g(n); for (int _ = n - 1; _--;) { int u, v; cin >> tie(u, v); --u, --v; g.add_edge({u, v, 1}); } g.build(0); vector<Fp> x(n); cin >> x; auto order = ALL(vector, iota(0, n)); sort(order, {}, [&](int v) { return pair(v ? g.in[g.pv[v]] : -1, g.in[v]); }); vector<int> rank(n); for (int i : iota(0, n)) { rank[order[i]] = i; } atcoder::lazy_segtree<Fp, op, e, F, mapping, composition, id> seg(n); for (int v : iota(0, n)) { seg.set(rank[v], x[v]); } while (q--) { int tp; cin >> tp; if (tp == 1) { int v; cin >> v; --v; cout << seg.get(rank[v]) << '\n'; } else if (tp == 2) { int v, k, c, d; cin >> tie(v, k, c, d); --v; assert(k == 1); if (v) { seg.apply(rank[g.pv[v]], {c, d}); } seg.apply(rank[v], {c, d}); if (int nc = g.adj[v].size() - (v != 0); nc) { int u = g.order[g.in[v] + 1]; seg.apply(rank[u], rank[u] + nc, {c, d}); } } else { int v, c, d; cin >> tie(v, c, d); --v; seg.apply(rank[v], {c, d}); if (1 < g.sub[v]) { int u = g.order[g.in[v] + 1]; seg.apply(rank[u], rank[u] + (g.sub[v] - 1), {c, d}); } } } } } // namespace } // namespace std::ranges::views using views::solve; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); solve(); } #else // __INCLUDE_LEVEL__ #include <atcoder/lazysegtree> #include <atcoder/modint> struct Graph { struct Edge { int src, dst; int64_t cost; int other(int v) const { __glibcxx_assert(v == src or v == dst); return src ^ dst ^ v; } }; std::vector<Edge> edges; std::vector<std::vector<std::pair<int, int>>> adj; Graph() {} explicit Graph(int n) : adj(n) {} int n() const { return std::size(adj); } int m() const { return std::size(edges); } int add_edge(const Edge& e, bool directed) { __glibcxx_assert(0 <= e.src and e.src < n()); __glibcxx_assert(0 <= e.dst and e.dst < n()); int id = m(); edges.push_back(e); adj[e.src].emplace_back(e.dst, id); if (not directed) adj[e.dst].emplace_back(e.src, id); return id; } }; struct DfsTree : Graph { using T = decltype(Edge::cost); std::vector<int> root; std::vector<int> pv; std::vector<int> pe; std::vector<int> order; std::vector<int> in; std::vector<int> out; std::vector<int> sub; std::vector<int> depth; std::vector<int> min_depth; std::vector<T> dist; std::vector<int> last; int num_trials; DfsTree() {} explicit DfsTree(int n) : Graph(n), root(n, -1), pv(n, -1), pe(n, -1), in(n, -1), out(n, -1), sub(n, -1), depth(n, -1), min_depth(n, -1), dist(n, std::numeric_limits<T>::max()), last(n, -1), num_trials(0) {} int add_edge(const Edge& e) { return Graph::add_edge(e, false); } void dfs(int r, bool clear_order = true) { __glibcxx_assert(0 <= r and r < n()); root[r] = r; pv[r] = -1; pe[r] = -1; if (clear_order) order.clear(); depth[r] = 0; dist[r] = T{}; dfs_impl(r); ++num_trials; } void dfs_all() { std::fill(std::begin(root), std::end(root), -1); for (int v = 0; v < n(); ++v) if (root[v] == -1) dfs(v, v == 0); } int deeper(int id) const { __glibcxx_assert(0 <= id and id < m()); int a = edges[id].src; int b = edges[id].dst; return depth[a] < depth[b] ? b : a; } bool is_tree_edge(int id) const { __glibcxx_assert(0 <= id and id < m()); return id == pe[deeper(id)]; } bool is_ancestor(int u, int v) const { __glibcxx_assert(0 <= u and u < n()); __glibcxx_assert(0 <= v and v < n()); return in[u] <= in[v] and out[v] <= out[u]; } private: void dfs_impl(int v) { in[v] = std::size(order); order.push_back(v); sub[v] = 1; min_depth[v] = depth[v]; last[v] = num_trials; for (auto&& [u, id] : adj[v]) { if (id == pe[v]) continue; if (last[u] == num_trials) { min_depth[v] = std::min(min_depth[v], depth[u]); continue; } root[u] = root[v]; pv[u] = v; pe[u] = id; depth[u] = depth[v] + 1; dist[u] = dist[v] + edges[id].cost; dfs_impl(u); sub[v] += sub[u]; min_depth[v] = std::min(min_depth[v], min_depth[u]); } out[v] = std::size(order); } }; struct HldTree : DfsTree { std::vector<int> head; HldTree() {} explicit HldTree(int n) : DfsTree(n), head(n, -1) {} void build(int r, bool clear_order = true) { __glibcxx_assert(0 <= r and r < n()); dfs(r, clear_order); order.erase(std::end(order) - sub[r], std::end(order)); head[r] = r; build_impl(r); } void build_all() { std::fill(std::begin(root), std::end(root), -1); for (int v = 0; v < n(); ++v) if (root[v] == -1) build(v, v == 0); } int lca(int u, int v) const { __glibcxx_assert(0 <= u and u < n()); __glibcxx_assert(0 <= v and v < n()); __glibcxx_assert(root[u] == root[v]); while (true) { if (in[u] > in[v]) std::swap(u, v); if (head[u] == head[v]) return u; v = pv[head[v]]; } } int d(int u, int v) const { __glibcxx_assert(0 <= u and u < n()); __glibcxx_assert(0 <= v and v < n()); __glibcxx_assert(root[u] == root[v]); return depth[u] + depth[v] - 2 * depth[lca(u, v)]; } T distance(int u, int v) const { __glibcxx_assert(0 <= u and u < n()); __glibcxx_assert(0 <= v and v < n()); __glibcxx_assert(root[u] == root[v]); return dist[u] + dist[v] - 2 * dist[lca(u, v)]; } int la(int v, int d) const { __glibcxx_assert(0 <= v and v < n()); __glibcxx_assert(0 <= d and d <= depth[v]); while (depth[head[v]] > d) v = pv[head[v]]; return order[in[head[v]] + (d - depth[head[v]])]; } int next(int src, int dst) const { __glibcxx_assert(0 <= src and src < n()); __glibcxx_assert(0 <= dst and dst < n()); __glibcxx_assert(root[src] == root[dst]); __glibcxx_assert(src != dst); if (not is_ancestor(src, dst)) return pv[src]; return la(dst, depth[src] + 1); } int next(int src, int dst, int k) const { __glibcxx_assert(0 <= src and src < n()); __glibcxx_assert(0 <= dst and dst < n()); __glibcxx_assert(root[src] == root[dst]); __glibcxx_assert(k >= 0); int v = lca(src, dst); if (k <= depth[src] - depth[v]) return la(src, depth[src] - k); k -= depth[src] - depth[v]; __glibcxx_assert(k <= depth[dst] - depth[v]); return la(dst, depth[v] + k); } template <class Function> void apply(int src, int dst, bool vertex, Function f) const { __glibcxx_assert(0 <= src and src < n()); __glibcxx_assert(0 <= dst and dst < n()); __glibcxx_assert(root[src] == root[dst]); int v = lca(src, dst); while (head[src] != head[v]) { f(in[src] + 1, in[head[src]]); src = pv[head[src]]; } if (vertex) f(in[src] + 1, in[v]); else if (src != v) f(in[src] + 1, in[v] + 1); auto rec = [&](auto self, int to) -> void { if (head[v] == head[to]) { if (v != to) f(in[v] + 1, in[to] + 1); return; } self(self, pv[head[to]]); f(in[head[to]], in[to] + 1); }; rec(rec, dst); } template <class Searcher> int search(int src, int dst, bool vertex, Searcher f) const { __glibcxx_assert(0 <= src and src < n()); __glibcxx_assert(0 <= dst and dst < n()); __glibcxx_assert(root[src] == root[dst]); int res = -1; apply(src, dst, vertex, [&](int l, int r) { if (res != -1) return; int i = f(l, r); if (l > r) std::swap(l, r); if (l <= i and i < r) res = vertex ? order[i] : pe[order[i]]; }); return res; } private: void build_impl(int v) { in[v] = std::size(order); order.push_back(v); auto pos = std::partition(std::begin(adj[v]), std::end(adj[v]), [&](auto&& e) { return e.second == pe[e.first]; }); auto it = std::max_element( std::begin(adj[v]), pos, [&](auto&& a, auto&& b) { return sub[a.first] < sub[b.first]; }); if (it != std::begin(adj[v])) std::iter_swap(std::begin(adj[v]), it); std::partition(pos, std::end(adj[v]), [&](auto&& e) { return e.second == pe[v]; }); for (auto&& [u, id] : adj[v]) { if (id != pe[u]) break; head[u] = u == adj[v].front().first ? head[v] : u; build_impl(u); } out[v] = std::size(order); } }; namespace std { template <class T1, class T2> istream& operator>>(istream& is, pair<T1, T2>& p) { return is >> p.first >> p.second; } template <class... Ts> istream& operator>>(istream& is, tuple<Ts...>& t) { return apply([&is](auto&... xs) -> istream& { return (is >> ... >> xs); }, t); } template <class... Ts> istream& operator>>(istream& is, tuple<Ts&...>&& t) { return is >> t; } template <class R, enable_if_t<!is_convertible_v<R, string>>* = nullptr> auto operator>>(istream& is, R&& r) -> decltype(is >> *begin(r)) { for (auto&& e : r) { is >> e; } return is; } template <class T1, class T2> ostream& operator<<(ostream& os, const pair<T1, T2>& p) { return os << p.first << ' ' << p.second; } template <class... Ts> ostream& operator<<(ostream& os, const tuple<Ts...>& t) { auto f = [&os](const auto&... xs) -> ostream& { [[maybe_unused]] auto sep = ""; ((os << exchange(sep, " ") << xs), ...); return os; }; return apply(f, t); } template <class R, enable_if_t<!is_convertible_v<R, string_view>>* = nullptr> auto operator<<(ostream& os, R&& r) -> decltype(os << *begin(r)) { auto sep = ""; for (auto&& e : r) { os << exchange(sep, " ") << e; } return os; } } // namespace std namespace atcoder { template <class T, internal::is_modint_t<T>* = nullptr> istream& operator>>(istream& is, T& x) { int v; is >> v; x = T::raw(v); return is; } template <class T, internal::is_modint_t<T>* = nullptr> ostream& operator<<(ostream& os, const T& x) { return os << x.val(); } } // namespace atcoder #endif // __INCLUDE_LEVEL__