#include #include #include #include #include #include using ll = int64_t; using std::cin, std::cout; // 定义最大节点数为5e5加5,以确保足够的空间 const ll maxn = 5e5 + 5; ll n, k; // n: 树的节点数,k: 暴龙的种类数 ll a[maxn]; // a[i]: 第i个节点的暴龙种类 ll ans[maxn]; // ans[i]: 第i种暴龙的红温值 std::vector> adj[maxn]; // adj[u]: 节点u的邻居及边权 std::map dp[maxn]; // dp[u][j]: 节点u到子树中种类j的最大距离 // 优化输入读取,提高IO速度 struct CinNum { char c; ll n, w; // 重载右移运算符以自定义输入方式 CinNum &operator>>(ll &num) { c = n = 0; w = 1; // 跳过非数字字符,记录负号 while (!isdigit(c = getchar())) { if (c == '-') w = -1; } // 读取数字 while (isdigit(c)) { n = n * 10 + (c - '0'); c = getchar(); } num = n * w; return *this; } } cinn; // 使用自定义的CinNum来替代标准输入 #define cin cinn /** * @brief 使用深度优先搜索 (DFS) 计算每种暴龙的红温值 * * @param fth 当前节点的父节点 * @param u 当前处理的节点 */ void dfs(const ll &fth, const ll &u) noexcept { // 初始化当前节点的dp,自己到自己距离为0 dp[u].emplace(a[u], 0); // 遍历所有邻接节点 for (const auto& [v, w] : adj[u]) { if (v == fth) continue; // 避免回到父节点 dfs(u, v); // 递归处理子节点 // 遍历子节点v的所有暴龙种类及其对应的最大距离 for (const auto& [kk, vv] : dp[v]) { // 如果当前节点u已经有这种暴龙类型,且子节点v也有 if ((dp[u][kk] > 0 || a[u] == kk) && (dp[v][kk] > 0 || a[v] == kk)) { // 更新ans[kk]为u和v子树中这种暴龙类型的最大距离 ans[kk] = std::max(ans[kk], dp[u][kk] + dp[v][kk] + w); } // 更新u节点到这种暴龙类型的最大距离 dp[u][kk] = std::max(dp[u][kk], dp[v][kk] + w); // 如果当前节点u本身就是这种暴龙类型,进一步更新ans[kk] if (a[u] == kk) { ans[kk] = std::max(ans[kk], dp[u][kk]); } } // 清空子节点v的dp以节省内存,因为已经合并到u的dp中了 dp[v].clear(); } } int main(){ // 读取节点数n和暴龙种类数k cin >> n >> k; // 读取每个节点的暴龙种类 for(ll i = 1; i <= n; i++) cin >> a[i]; // 读取树的边信息,并构建邻接表 for(ll i = 1; i < n; i++){ ll u, v, w; cin >> u >> v >> w; adj[u].emplace_back(v, w); adj[v].emplace_back(u, w); } // 从节点1开始DFS遍历整棵树,假设节点1为根节点,父节点为0 dfs(0, 1); // 输出每种暴龙的红温值 for(ll i = 1; i <= k; i++) cout << ans[i] << '\n'; }