Skip to Content

DP en árboles - Resolver para todas las raíces

HechoFuenteNombreDificultadTagsSolución
CSESTree Distances IFácilTree, DFSSolución

Solución - Tree Distances I

Recursos
FuenteRecursoNotas
CPH14.3 - All Longest Paths

Es una técnica común calcular dos arreglos de DP en algunos problemas de DP sobre árboles. Normalmente un arreglo de DP se encarga de calcular resultados dentro del subárbol con raíz en ii. El otro arreglo de DP calcula resultados fuera del subárbol con raíz en ii.

El problema foco nos pide hallar, para cada nodo, la distancia máxima a otro nodo. Podemos partir el problema en dos partes.

Definimos f[x]f[x] como la distancia máxima desde el nodo xx a cualquier nodo del subárbol con raíz en xx, y g[x]g[x] como la distancia máxima desde el nodo xx a cualquier nodo fuera del subárbol con raíz en xx. Entonces la respuesta para el nodo xx es max(f[x],g[x])\max(f[x],g[x]).

  • f[x]f[x] se puede calcular con un DFS, ya que f[x]=max(f[c])+1f[x]=\max(f[c])+1, donde cc es un hijo de xx.
  • g[x]g[x] también se puede calcular con un DFS como g[c]=max(g[x]+1,f[d]+2)g[c]=\max(g[x]+1, f[d]+2), donde cc y dd son ambos hijos de xx con cdc \neq d.

Para calcular gg en tiempo lineal, podemos definir otro arreglo hh tal que h[x]h[x] sea la mayor distancia desde el nodo xx a cualquier nodo del subárbol con raíz en xx excluyendo el subárbol hijo que contribuyó a f[x]f[x]. Así, si f[x]f[x] se transiciona desde la rama con cc, g[c]=max(g[x]+1,h[x]+1)g[c]=\max(g[x]+1,h[x]+1). En caso contrario g[c]=max(g[x]+1,f[x]+1)g[c]=\max(g[x]+1,f[x]+1).

#include <bits/stdc++.h> using namespace std; vector<int> graph[200001]; int fir[200001], sec[200001], ans[200001]; void dfs1(int node = 1, int parent = 0) { for (int i : graph[node]) if (i != parent) { dfs1(i, node); if (fir[i] + 1 > fir[node]) { sec[node] = fir[node]; fir[node] = fir[i] + 1; } else if (fir[i] + 1 > sec[node]) { sec[node] = fir[i] + 1; } } } void dfs2(int node = 1, int parent = 0, int to_p = 0) { ans[node] = max(to_p, fir[node]); for (int i : graph[node]) if (i != parent) { if (fir[i] + 1 == fir[node]) dfs2(i, node, max(to_p, sec[node]) + 1); else dfs2(i, node, ans[node] + 1); } } int main() { ios_base::sync_with_stdio(0); cin.tie(0); int n; cin >> n; for (int i = 1; i < n; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } dfs1(); dfs2(); for (int i = 1; i <= n; i++) cout << ans[i] << ' '; return 0; }
import java.io.*; import java.util.*; public class Main { public static ArrayList<Integer> g[]; public static Pair maxl1[]; public static Pair maxl2[]; public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int N = Integer.parseInt(br.readLine()); g = new ArrayList[N + 1]; maxl1 = new Pair[N + 1]; maxl2 = new Pair[N + 1]; for (int i = 0; i <= N; i++) { g[i] = new ArrayList<Integer>(); maxl1[i] = new Pair(0, 0); maxl2[i] = new Pair(0, 0); } for (int i = 1; i < N; i++) { StringTokenizer st = new StringTokenizer(br.readLine()); int a = Integer.parseInt(st.nextToken()); int b = Integer.parseInt(st.nextToken()); g[a].add(b); g[b].add(a); } dfs1(1, 0); dfs2(1, 0); for (int i = 1; i <= N; i++) { System.out.print(maxl1[i].f + " "); } } public static int dfs1(int i, int p) { int ret = 0; for (int next : g[i]) { if (next != p) { int c = dfs1(next, i); ret = Math.max(ret, c + 1); if (c + 1 > maxl1[i].f) { maxl2[i] = maxl1[i]; maxl1[i] = new Pair(c + 1, next); } else if (c + 1 > maxl2[i].f) { maxl2[i] = new Pair(c + 1, next); } } } return ret; } public static void dfs2(int i, int p) { if (p != 0) { if (maxl1[p].s == i) { if (maxl2[p].f + 1 > maxl1[i].f) { maxl2[i] = maxl1[i]; maxl1[i] = new Pair(maxl2[p].f + 1, p); } else if (maxl2[p].f + 1 > maxl2[i].f) { maxl2[i] = new Pair(maxl2[p].f + 1, p); } } else { if (maxl1[p].f + 1 > maxl1[i].f) { maxl2[i] = maxl1[i]; maxl1[i] = new Pair(maxl1[p].f + 1, p); } else if (maxl1[p].f + 1 > maxl2[i].f) { maxl2[i] = new Pair(maxl1[p].f + 1, p); } } } for (int next : g[i]) { if (next != p) dfs2(next, i); } } static class Pair { public int f, s; public Pair(int f, int s) { this.f = f; this.s = s; } } }

Problemas

HechoFuenteNombreDificultadTagsSolución
CFTree PaintingFácilDPSolución
ACSubtreeNormalDPSolución
Balkan OI2017 - City AttractionsNormalDP, Functional GraphSolución
GoldDirectory TraversalNormalDP, TreeSolución
APIO2010 - PatrolDifícilDP, Casework
IZhO2017 - Hard routeDifícilDPSolución
APIO2014 - BeadsMuy difícilDP, CaseworkSolución
CEOI2020 - Star TrekMuy difícilDP, Math
PlatinumCow At LargeMuy difícilDP, TreeSolución