Official
F - 構文木/Parse Tree Editorial
by
F - 構文木/Parse Tree Editorial
by
Nyaan
この問題は深さ優先探索を利用すれば解くことが出来ます。
具体的に手順を説明します。各頂点 \(v\) に対して \(dp_v\) を「その頂点に書きこまれる値を \(998244353\) で割った余り」として定義して、これを計算していくことを考えます。 最終的な問題の答えは \(dp_1\) です。
\(dp_v\) は次のようにすれば求まります。\(v\) が葉の頂点である場合は \(dp_v = S[v]\) です。そうでない場合は、\(v\) の子を \(c_1, c_2\) として、\(dp_{c_1}, dp_{c_2}\) を計算した後に \((dp_{c_1} + dp_{c_2}) \bmod{998244353}\) あるいは \((dp_{c_1} \times dp_{c_2}) \bmod{998244353}\) を計算すればよいです。
\(dp_1\) は根の頂点に対応する値なので、\(dp_v\) を木の葉から根の方向へ向けて 1 つずつ確定させていくことができれば \(dp_1\) を計算することが出来て、これは深さ優先探索を用いれば実装することが出来ます。
計算量は \(\mathrm{O}(N)\) で十分高速です。
- 実装例(C++)
#include <iostream>
#include <string>
#include <vector>
using namespace std;
constexpr int nmax = 2e5 + 10;
int N, mod = 998244353;
vector<int> g[nmax];
string S[nmax];
long long dfs(int c) {
if (g[c].empty()) return stoll(S[c]) % mod;
long long a = dfs(g[c][0]), b = dfs(g[c][1]);
return (S[c] == "+" ? a + b : a * b) % mod;
}
int main() {
cin >> N;
for (int i = 2, p; i <= N; i++) g[cin >> p, p].push_back(i);
for (int i = 1; i <= N; i++) cin >> S[i];
cout << dfs(1) << endl;
}
posted:
last update: