結果
問題 | No.2340 Triple Tree Query (Easy) |
ユーザー |
![]() |
提出日時 | 2023-06-02 23:05:33 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 321 ms / 5,000 ms |
コード長 | 10,782 bytes |
コンパイル時間 | 4,271 ms |
コンパイル使用メモリ | 296,564 KB |
実行使用メモリ | 26,672 KB |
最終ジャッジ日時 | 2024-12-28 21:50:41 |
合計ジャッジ時間 | 15,820 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 1 |
other | AC * 36 |
ソースコード
#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::viewsusing 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 stdnamespace 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__