結果
問題 | No.2949 Product on Tree |
ユーザー |
|
提出日時 | 2024-11-04 10:30:04 |
言語 | PyPy3 (7.3.15) |
結果 |
TLE
|
実行時間 | - |
コード長 | 3,816 bytes |
コンパイル時間 | 367 ms |
コンパイル使用メモリ | 82,240 KB |
実行使用メモリ | 287,188 KB |
最終ジャッジ日時 | 2024-11-04 10:30:34 |
合計ジャッジ時間 | 24,189 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | TLE * 9 -- * 37 |
ソースコード
import pypyjitimport syspypyjit.set_param('max_unroll_recursion=-1')sys.setrecursionlimit(2000000)class Rerooting:"""Rerooting クラスは、木の再根付き問題を解くためのクラスです。木の各頂点を根とする部分木の情報を効率的に計算します。based on: https://algo-logic.info/tree-dpAttributes:G: List[List[Edge]]: 隣接リスト。dp: List[List[DP]]: dp[v][i]: 頂点vから出るi番目の有向辺に対応する部分木のDP。ans: List[DP]: ans[v]: 頂点vを根とする木の答え。Methods:add_edge(a, b): 頂点aと頂点bの間に辺を追加します。build(): 木の再根付きDPを構築します。dfs(v, p): 深さ優先探索を用いて部分木のDPを計算します。bfs(v, dp_p, p): 幅優先探索を用いて部分木のDPを計算します。Parameters:N: int: 頂点数。class DP: DP の型。identity: DP の単位元。class Edge: 辺の型。merge(d1, d2): 2つのDPをマージします。add_root(d): 部分木のDPに根を追加します。"""# region 問題ごとに変更する部分class DP: # DP の型def __init__(self, dp_):self.dp = dp_identity = DP(0) # 単位元(末端の値は add_root(identity) になるので注意)class Edge:def __init__(self, to):self.to = todef merge(self, d1: DP, d2: DP) -> DP:return self.DP(d1.dp + d2.dp)def add_root(self, d: DP, v: int) -> DP:return self.DP((d.dp + 1) * C[v] % MOD)# endregion# region slvdef __init__(self, N: int):self.G = [[] for _ in range(N)]self.dp = [[] for _ in range(N)]self.ans = [self.identity] * Ndef add_edge(self, a: int, b: int):self.G[a].append(self.Edge(b))def build(self):self.dfs(0) # 普通に木DPself.bfs(0, self.identity) # 残りの部分木に対応するDPを計算def dfs(self, v: int, p: int = -1) -> DP: # 頂点v, 親pdp_cum = self.identitydeg = len(self.G[v])self.dp[v] = [self.identity] * degfor i in range(deg):u = self.G[v][i].toif u == p:continueself.dp[v][i] = self.dfs(u, v)dp_cum = self.merge(dp_cum, self.dp[v][i])return self.add_root(dp_cum, v)def bfs(self, v: int, dp_p: DP, p: int = -1): # bfs だが、実装が楽なので中身は dfs になっているdeg = len(self.G[v])for i in range(deg): # 前のbfsで計算した有向辺に対応する部分木のDPを保存if self.G[v][i].to == p:self.dp[v][i] = dp_pdp_l = [self.identity] * (deg + 1) # 累積mergedp_r = [self.identity] * (deg + 1) # 累積mergefor i in range(deg):dp_l[i + 1] = self.merge(dp_l[i], self.dp[v][i])for i in range(deg - 1, -1, -1):dp_r[i] = self.merge(dp_r[i + 1], self.dp[v][i])self.ans[v] = self.add_root(dp_l[deg], v) # 頂点 v の答えfor i in range(deg): # 一つ隣の頂点に対しても同様に計算u = self.G[v][i].toif u == p:continueself.bfs(u, self.add_root(self.merge(dp_l[i], dp_r[i + 1]), v), v)# endregionN = int(input())C = list(map(int, input().split()))MOD = 998244353r = Rerooting(N)for _ in range(N - 1):u, v = map(int, input().split())u -= 1v -= 1r.add_edge(u, v)r.add_edge(v, u)r.build()A = r.ansans = 0for a in A:ans += a.dpans %= MODans -= sum(C)ans *= pow(2, MOD - 2, MOD)ans %= MODprint(ans)