[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;
}
本文来自一名高中生,作者:To_Carpe_Diem

浙公网安备 33010602011771号