結果
問題 | No.2949 Product on Tree |
ユーザー |
![]() |
提出日時 | 2024-11-02 17:51:21 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 543 ms / 2,000 ms |
コード長 | 3,620 bytes |
コンパイル時間 | 4,245 ms |
コンパイル使用メモリ | 269,664 KB |
実行使用メモリ | 72,700 KB |
最終ジャッジ日時 | 2024-11-02 17:51:54 |
合計ジャッジ時間 | 29,147 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 46 |
ソースコード
#include<bits/stdc++.h>#include<atcoder/modint>// g[from] contains outgoing edges (to, edgeid(from, to))// (E, op, e) is commutative monoid// ~edgeid(from, to) == edgeid(to, from)// return calculator of dp(r, v)template<class V, class E>auto rerootingdp(auto op, E e, auto put_edge, auto put_vertex, const std::vector<std::vector<std::pair<int, int>>> &g, int root = 0){struct dp {// dp(r, v) : root is r, dp of subtree v// ans[v] = dp(v, v)// from[v] = dp(v, par(v))// to[v] = dp(par(v), v)// from[root] and to[root] is undefinedstd::vector<V> ans, from, to;std::vector<int> down, up;std::vector<std::vector<int>> childs;bool is_in_subtree(int r, int v){return down[r] < down[v] && up[v] <= up[r];}V operator()(int r, int v){if (r == v) return ans[v];if (!is_in_subtree(v, r)) return to[v];int le = 0, ri = childs[v].size();while (ri - le > 1){int md = (le + ri) / 2;if (down[childs[v][md]] <= down[r]){le = md;}else {ri = md;}}return from[childs[v][le]];}};int n = g.size();std::vector<E> from(n, e), to(n, e);std::vector<V> dp_to(n);std::vector<std::vector<int>> childs(n);std::vector<int> down(n), up(n);int t = 0;auto dfs = [&](auto sfs, int v, int f) -> void {down[v] = t++;childs[v].reserve(g[v].size());for (auto [c, eid] : g[v]){if (c == f) continue;childs[v].emplace_back(c);sfs(sfs, c, v);dp_to[c] = put_vertex(to[c], c);to[c] = put_edge(dp_to[c], eid);to[v] = op(to[v], to[c]);}up[v] = t;};dfs(dfs, root, -1);std::vector<V> dp_ans(n), dp_from(n);std::vector<E> inner(n);auto bfs = [&](auto sfs, int v, int f) -> void {int sz = g[v].size();inner[sz] = e;int i = sz-1;for (auto [c, eid] : g[v] | std::views::reverse){if (c == f) continue;inner[i] = op(inner[i+1], to[c]);i--;}dp_ans[v] = put_vertex(op(inner[++i], from[v]), v);E rui = e;for (auto [c, eid] : g[v]){if (c == f) continue;dp_from[c] = put_vertex(op(op(rui, inner[++i]), from[v]), v);from[c] = put_edge(dp_from[c], ~eid);rui = op(rui, to[c]);}for (auto [c, eid] : g[v]){if (c == f) continue;sfs(sfs, c, v);}};bfs(bfs, root, -1);return dp{dp_ans, dp_from, dp_to, down, up, childs};}using mint = atcoder::modint998244353;int main(){int n; std::cin >> n;std::vector<mint> a(n);for (auto &e : a){int x; std::cin >> x;e = x;}std::vector<std::vector<std::pair<int,int>>> g(n);for (int i = 0; i < n-1; i++){int u, v; std::cin >> u >> v; u--, v--;g[u].emplace_back(v,i);g[v].emplace_back(u,~i);}auto op = [&](mint l, mint r){return l + r;};auto pute = [&](mint v, int){return v;};auto putv = [&](mint e, int v){return e * a[v] + a[v];};auto dp = rerootingdp<mint,mint>(op,mint(0),pute,putv,g);mint ans = 0;for (int i = 0; i < n; i++){ans += dp(i,i);ans -= a[i];}ans /= 2;std::cout << ans.val() << '\n';}