[Non]树上乘法

[Non]树上乘法

大意

给定若干次操作,每次将 \(u \to v\) 的路径上的点的点权值都乘上 \(k\),最终求最大的边的编号。

思路

显然,你一直乘法一定会炸,对于加法运算,我们可以转化为加法与减法进行差分,对于乘法,我们是否可以考虑转为加法呢?答案是可以,转化为对数运算不就行了吗,每次加上 \(\log(k)\),这样不就不会超出范围了嘛。

然后,依旧树上差分,直接做就好。

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 300010;
vector<int> g[N];
int fa[N][23], dep[N], n, q;
void dfs(int u) {
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if (v == fa[u][0]) continue;
        fa[v][0] = u;
        dep[v] = dep[u] + 1;
        dfs(v);
    }
}
void initLca() {
    for (int i = 1; i <= 22; ++i) {
        for (int j = 1; j <= n; ++j) {
            fa[j][i] = fa[fa[j][i - 1]][i - 1];
        }
    }
    return;
}
int lca(int x, int y) {
    if (dep[x] < dep[y]) swap(x, y);
    for (int i = 22; i >= 0; i--)
        if (dep[fa[x][i]] >= dep[y]) x = fa[x][i];
    if (x == y) return x;
    for (int i = 22; i >= 0; i--)
        if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
    return fa[x][0];
}
double val[N];
void dfs2(int u) {
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if (v == fa[u][0]) continue;
        dfs2(v);
        val[u] += val[v];
    }
}
int main() {
    cin >> n >> q;
    int u, v, w;
    for (int i = 2; i <= n; ++i) {
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    fa[1][0] = 1;
    dfs(1);
    initLca();
    while (q--) {
        cin >> u >> v >> w;
        int l = lca(u, v);
        val[u] += log(w);
        val[v] += log(w);
        val[l] -= 2 * log(w);
    }
    dfs2(1);
    int ans = 0;
    for(int i = 2;i <= n;i ++){
        if(val[ans] < val[i]) ans = i;
    }
    cout << fa[ans][0] << ' ' << ans << '\n';
    return 0;
}
posted @ 2025-12-12 23:09  To_Carpe_Diem  阅读(0)  评论(0)    收藏  举报