結果
| 問題 | No.3250 最小公倍数 | 
| コンテスト | |
| ユーザー |  | 
| 提出日時 | 2025-08-06 11:55:13 | 
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) | 
| 結果 | 
                                TLE
                                 
                            (最新) 
                                AC
                                 
                            (最初) | 
| 実行時間 | - | 
| コード長 | 3,551 bytes | 
| コンパイル時間 | 968 ms | 
| コンパイル使用メモリ | 90,460 KB | 
| 実行使用メモリ | 61,388 KB | 
| 最終ジャッジ日時 | 2025-10-16 16:08:36 | 
| 合計ジャッジ時間 | 8,336 ms | 
| ジャッジサーバーID (参考情報) | judge2 / judge5 | 
(要ログイン)
| ファイルパターン | 結果 | 
|---|---|
| sample | -- * 1 | 
| other | TLE * 1 -- * 21 | 
ソースコード
#include <iostream>
#include <vector>
#include <map>
#include <numeric>
#include <algorithm>
using namespace std;
// 定数
const int MAXN = 500005;
const int MAXA = 1000001;
const int MOD = 998244353;
// グローバル変数
vector<int> adj[MAXN];
int a[MAXN];
int sz[MAXN];
long long ans[MAXN];
int spf[MAXA]; // Smallest Prime Factor
// エラトステネスの篩で最小の素因数を求める
void sieve() {
    iota(spf, spf + MAXA, 0); // spf[i] = i で初期化
    for (int i = 2; i * i < MAXA; ++i) {
        if (spf[i] == i) { // iが素数
            for (int j = i * i; j < MAXA; j += i) {
                if (spf[j] == j) { // まだ最小素因数が更新されていない
                    spf[j] = i;
                }
            }
        }
    }
}
// 高速な素因数分解
map<int, int> get_factors(int n) {
    map<int, int> factors;
    while (n != 1) {
        factors[spf[n]]++;
        n /= spf[n];
    }
    return factors;
}
// mod上のべき乗
long long power(long long base, long long exp) {
    long long res = 1;
    base %= MOD;
    while (exp > 0) {
        if (exp % 2 == 1) res = (res * base) % MOD;
        base = (base * base) % MOD;
        exp /= 2;
    }
    return res;
}
// DFSで部分木のサイズを計算し、重い子を特定する
void dfs_size(int u, int p) {
    sz[u] = 1;
    int heavy_child_idx = -1;
    int max_sz = 0;
    for (size_t i = 0; i < adj[u].size(); ++i) {
        int v = adj[u][i];
        if (v == p) continue;
        dfs_size(v, u);
        sz[u] += sz[v];
        if (sz[v] > max_sz) {
            max_sz = sz[v];
            heavy_child_idx = i;
        }
    }
    // 重い子を隣接リストの先頭に持ってくる
    if (heavy_child_idx != -1) {
        swap(adj[u][0], adj[u][heavy_child_idx]);
    }
}
// DSU on Trees を用いたメインのDFS
map<int, int> dfs_solve(int u, int p) {
    map<int, int> u_lcm_factors;
    // 重い子が存在すれば、その結果を再利用する
    int heavy_child = -1;
    if (!adj[u].empty() && adj[u][0] != p) {
        heavy_child = adj[u][0];
    }
    if (heavy_child != -1) {
        u_lcm_factors = dfs_solve(heavy_child, u);
    }
    // 軽い子の結果をマージする
    for (int v : adj[u]) {
        if (v == p || v == heavy_child) continue;
        map<int, int> lc_lcm_factors = dfs_solve(v, u);
        for (auto const& [prime, exponent] : lc_lcm_factors) {
            u_lcm_factors[prime] = max(u_lcm_factors[prime], exponent);
        }
    }
    // 現在のノードの重みをマージする
    map<int, int> current_factors = get_factors(a[u]);
    for (auto const& [prime, exponent] : current_factors) {
        u_lcm_factors[prime] = max(u_lcm_factors[prime], exponent);
    }
    // uを根とする部分木の答えを計算する
    long long current_ans = 1;
    for (auto const& [prime, exponent] : u_lcm_factors) {
        current_ans = (current_ans * power(prime, exponent)) % MOD;
    }
    ans[u] = current_ans;
    return u_lcm_factors;
}
int main() {
    // 高速化
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    sieve();
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    for (int i = 0; i < n - 1; ++i) {
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    // 1を根として処理を開始
    dfs_size(1, 0);
    dfs_solve(1, 0);
    for (int i = 1; i <= n; ++i) {
        cout << ans[i] << "\n";
    }
    return 0;
}
            
            
            
        