Parsa's Humongous Tree
Explicación
Sin pérdida de generalidad, supongamos que ya calculamos los mejores valores de belleza para todos los vecinos del vértice .
Sea el que guarda y , y el que guarda los valores de belleza de todos los vértices adyacentes a .
Por ejemplo, pondremos
Digamos que seleccionamos , lo que nos da una belleza de . ¿Podemos hacerlo mejor que esto?
Intuitivamente, para cualquier que elijamos como valor de belleza de , si hay más elementos mayores que este , hacer lo más pequeño posible sería más óptimo (aumentando las diferencias de estos elementos) y viceversa. Nótese que en un caso donde el número de valores de belleza mayores es el mismo que el de valores de belleza menores, poner en el mínimo o el máximo nunca disminuye la respuesta. Mover siempre aumenta la distancia para el otro extremo de los valores de belleza.
Esta observación es todo lo que necesitamos. Como poner en o es siempre óptimo, lo manejaremos con DP.
Si guarda la suma máxima de valores de belleza en el subárbol enraizado en cuando el “tipo de belleza” de es . Como el vértice solo puede tomar dos valores, será igual a cuando el valor de belleza de es y cuando el valor de belleza de es .
Nuestras transiciones son:
Esto esencialmente significa:
Si tiene la belleza :
belleza si tiene un valor de belleza de , belleza si tiene un valor de belleza de )
Si tiene la belleza :
belleza si tiene un valor de belleza de , belleza si tiene un valor de belleza de )
Implementación
Complejidad temporal:
#include <algorithm>
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::pair;
using std::vector;
vector<vector<int>> adj;
vector<pair<int, int>> range;
vector<vector<long long>> dp;
// return optimal beauty value for vertex u with subtree v
long long mx_beauty(int u, int v, bool type) {
if (!type) {
long long swtch = dp[v][1] + abs(range[u].first - range[v].second);
long long sm = dp[v][0] + abs(range[u].first - range[v].first);
return std::max(swtch, sm);
} else {
long long swtch = dp[v][1] + abs(range[u].second - range[v].second);
long long sm = dp[v][0] + abs(range[u].second - range[v].first);
return std::max(swtch, sm);
}
}
void calculate_dp(int u, int par) {
for (int v : adj[u]) {
if (v == par) { continue; }
calculate_dp(v, u);
dp[u][0] += mx_beauty(u, v, 0);
dp[u][1] += mx_beauty(u, v, 1);
}
}
int main() {
std::cin.tie(0)->sync_with_stdio(0);
int test_num;
std::cin >> test_num;
for (int t = 0; t < test_num; t++) {
int n;
std::cin >> n;
range.clear();
adj.assign(n, {});
dp.assign(n, vector<long long>(2, 0));
for (int i = 0; i < n; i++) {
int l;
int r;
std::cin >> l >> r;
range.push_back(make_pair(l, r));
}
for (int i = 0; i < n - 1; i++) {
int u;
int v;
std::cin >> u >> v;
adj[--u].push_back(--v);
adj[v].push_back(u);
}
calculate_dp(0, -1);
cout << std::max(dp[0][0], dp[0][1]) << endl;
}
}import java.io.*;
import java.util.*;
public class ParsasHumongousTree {
private static List<List<Integer>> adj = new ArrayList<>();
private static int[] l, r;
private static long[][] dp;
public static void main(String[] args) {
Kattio io = new Kattio();
int t = io.nextInt();
for (int tc = 0; tc < t; tc++) {
int n = io.nextInt();
l = new int[n + 1];
r = new int[n + 1];
dp = new long[n + 1][2];
adj.clear();
for (int i = 1; i <= n; i++) {
l[i] = io.nextInt();
r[i] = io.nextInt();
}
for (int i = 0; i <= n; i++) { adj.add(new ArrayList<>()); }
for (int i = 0; i < n - 1; i++) {
int u = io.nextInt(), v = io.nextInt();
adj.get(u).add(v);
adj.get(v).add(u);
}
calculateDP(1, -1);
io.println(Math.max(dp[1][0], dp[1][1]));
}
io.flush();
}
private static void calculateDP(int u, int par) {
for (int v : adj.get(u)) {
// Continue if `v` is `u`'s parent.
if (v == par) { continue; }
// Calculate the DP values for 'v'.
calculateDP(v, u);
// DP transitions for 'u'.
dp[u][0] += maxBeauty(u, v, false);
dp[u][1] += maxBeauty(u, v, true);
}
}
// Return optimal beauty value for vertex u with subtree v.
private static long maxBeauty(int u, int v, boolean type) {
if (!type) {
long swtch = dp[v][1] + Math.abs(l[u] - r[v]);
long sm = dp[v][0] + Math.abs(l[u] - l[v]);
return Math.max(swtch, sm);
} else {
long swtch = dp[v][1] + Math.abs(r[u] - r[v]);
long sm = dp[v][0] + Math.abs(r[u] - l[v]);
return Math.max(swtch, sm);
}
}
// CodeSnip{Kattio}
}