結果

問題 No.2360 Path to Integer
ユーザー 👑 hitonanodehitonanode
提出日時 2023-06-23 23:37:33
言語 C++23
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 150 ms / 2,500 ms
コード長 4,434 bytes
コンパイル時間 2,705 ms
コンパイル使用メモリ 191,448 KB
実行使用メモリ 23,400 KB
最終ジャッジ日時 2023-09-13 18:46:59
合計ジャッジ時間 4,989 ms
ジャッジサーバーID
(参考情報)
judge14 / judge12
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
4,376 KB
testcase_01 AC 1 ms
4,376 KB
testcase_02 AC 1 ms
4,380 KB
testcase_03 AC 1 ms
4,380 KB
testcase_04 AC 2 ms
4,376 KB
testcase_05 AC 1 ms
4,376 KB
testcase_06 AC 2 ms
4,380 KB
testcase_07 AC 3 ms
4,376 KB
testcase_08 AC 11 ms
4,880 KB
testcase_09 AC 139 ms
21,788 KB
testcase_10 AC 117 ms
23,396 KB
testcase_11 AC 121 ms
23,400 KB
testcase_12 AC 83 ms
21,816 KB
testcase_13 AC 150 ms
21,728 KB
testcase_14 AC 147 ms
21,104 KB
testcase_15 AC 138 ms
21,736 KB
testcase_16 AC 126 ms
21,036 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <chrono>
#include <cmath>
#include <complex>
#include <deque>
#include <forward_list>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;


#include <atcoder/modint>
using mint = atcoder::modint998244353;

#include <cassert>
#include <cstdlib>
#include <utility>
#include <vector>

// Rerooting
// Reference:
// - https://atcoder.jp/contests/abc222/editorial/2749
// - https://null-mn.hatenablog.com/entry/2020/04/14/124151
template <class Edge, class St, class Ch, Ch (*merge)(Ch, Ch), Ch (*f)(St, int, Edge),
          St (*g)(Ch, int), Ch (*e)()>
struct rerooting {
    int n_;
    std::vector<int> par, visited;
    std::vector<std::vector<std::pair<int, Edge>>> to;
    std::vector<St> dp_subtree;
    std::vector<St> dp_par;
    std::vector<St> dpall;
    rerooting(const std::vector<std::vector<std::pair<int, Edge>>> &to_)
        : n_(to_.size()), par(n_, -1), visited(n_, 0), to(to_) {
        for (int i = 0; i < n_; ++i) dp_subtree.push_back(g(e(), i));
        dp_par = dpall = dp_subtree;
    }

    void run_connected(int root) {
        if (visited[root]) return;
        visited[root] = 1;
        std::vector<int> visorder{root};

        for (int t = 0; t < int(visorder.size()); ++t) {
            int now = visorder[t];
            for (const auto &edge : to[now]) {
                int nxt = edge.first;
                if (visited[nxt]) continue;
                visorder.push_back(nxt);
                visited[nxt] = 1;
                par[nxt] = now;
            }
        }

        for (int t = int(visorder.size()) - 1; t >= 0; --t) {
            int now = visorder[t];
            Ch ch = e();
            for (const auto &edge : to[now]) {
                int nxt = edge.first;
                if (nxt == par[now]) continue;
                ch = merge(ch, f(dp_subtree[nxt], nxt, edge.second));
            }
            dp_subtree[now] = g(ch, now);
        }

        std::vector<Ch> left;
        for (int now : visorder) {
            int m = int(to[now].size());
            left.assign(m + 1, e());
            for (int j = 0; j < m; j++) {
                int nxt = to[now][j].first;
                const St &st = (nxt == par[now] ? dp_par[now] : dp_subtree[nxt]);
                left[j + 1] = merge(left[j], f(st, nxt, to[now][j].second));
            }
            dpall[now] = g(left.back(), now);

            Ch rprod = e();
            for (int j = m - 1; j >= 0; --j) {
                int nxt = to[now][j].first;
                if (nxt != par[now]) dp_par[nxt] = g(merge(left[j], rprod), now);

                const St &st = (nxt == par[now] ? dp_par[now] : dp_subtree[nxt]);
                rprod = merge(f(st, nxt, to[now][j].second), rprod);
            }
        }
    }

    void run() {
        for (int i = 0; i < n_; ++i) {
            if (!visited[i]) run_connected(i);
        }
    }

    const St &get_subtree(int root_, int par_) const {
        if (par_ < 0) return dpall.at(root_);
        if (par.at(root_) == par_) return dp_subtree.at(root_);
        if (par.at(par_) == root_) return dp_par.at(par_);
        std::exit(1);
    }
};

vector<string> A;

struct S {
    mint num = 0;
    mint sum = 0;
};
S e() { return S{}; }
using Edge = tuple<>;

S merge(S l, S r) { return S{l.num + r.num, l.sum + r.sum}; }

S f(S x, int, Edge) { return x; }

S g(S x, int v_id) {
    for (const auto &c : A.at(v_id)) x.sum *= 10;
    x.num += 1;
    x.sum += x.num * std::stoll(A.at(v_id));
    return x;
}

int main() {
    cin.tie(nullptr), ios::sync_with_stdio(false);
    int N;
    cin >> N;
    A.resize(N);
    for (auto &x : A) cin >> x;

    vector<vector<pair<int, Edge>>> to(N);
    for (int e = 0; e < N - 1; ++e) {
        int a, b;
        cin >> a >> b;
        --a, --b;
        to.at(a).push_back({b, {}});
        to.at(b).push_back({a, {}});
    }

    rerooting<Edge, S, S, merge, f, g, e> rr(to);
    rr.run();
    mint ret = 0;
    for (const auto &v : rr.dpall) ret += v.sum;
    cout << ret.val() << endl;
}
0