¡Árbol!#12252

¡Árbol! (Editorial)

Autor del Problema:

Timosh

Preparado por:

Hasan Saleh (MathModel)

Editado por:

Hasan Saleh (MathModel)

Solución

Llamamos a un nodo una hoja si tiene grado . Sea el número total de hojas en el árbol.

Raíz el árbol en . Para cada nodo , sea el número de hojas dentro del subárbol de (con respecto a esta raíz). Podemos calcular mediante un DFS:

s[v] \;=\; [\deg(v)=1] \;+\; \sum_{u\in \text{hijos}(v)} s[u].

Considera cualquier arista donde es el padre de . Si cortamos esta arista, aparecen dos componentes:

- El lado tiene hojas, pero el grado de disminuye en . Un nodo se convierte en hoja si y solo si su grado era , y una hoja deja de ser hoja si y solo si su grado era . Por lo tanto, el conteo de hojas en el lado después del corte es

A \;=\; s[v] \;+\; [\deg(v)=2] \;-\; [\deg(v)=1].

- El lado tiene L-s[v] hojas, y pierde una arista incidente, por lo que su grado también disminuye en . Así, el conteo de hojas en el lado después del corte es

B \;=\; (L-s[v]) \;+\; [\deg(p)=2] \;-\; [\deg(p)=1].

Una arista es equilibrada si A=B. Podemos calcular L=s[1] desde el primer DFS, luego en un segundo DFS sobre las aristas padre-hijo, probar la igualdad anterior y contar cuántas veces se cumple.

Esquema de Corrección

Cortar cambia el estado de hoja solo en los extremos y (todos los demás mantienen el mismo grado), por lo que ajustar por +[\deg=2]-[\deg=1] es tanto necesario como suficiente. Dado que y L-s[v] cuentan hojas estrictamente dentro de cada lado antes de considerar los cambios de grado de los extremos, A=B caracteriza exactamente las aristas equilibradas.

Complejidad por prueba (dos recorridos DFS).

#include <bits/stdc++.h>
using namespace std;

#define int int64_t
using vi=vector<int>;

void solve(){
    int n;cin>>n;
    vector<vi> g(n+1);
    for(int i=0,u,v;i<n-1;i++){
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    vector<int> s(n+1);
    vector<char> vis(n+1,0);

    auto tour= [&](auto self,int v,int p)->void{
        vis[v]=1;
        s[v]+= (int)g[v].size()==1;
        for(int u:g[v]) if(u!=p) self(self,u,v), s[v]+=s[u];
    };
    tour(tour,1,0);
    int L=s[1], ans=0;
    fill(vis.begin(),vis.end(),0);

    auto dfs= [&](auto self,int v,int p)->void{
        vis[v]=1;
        for(int u:g[v]) if(u!=p){
            int A = s[u] + ((int)g[u].size()==2) - ((int)g[u].size()==1);
            int B = L - s[u] + ((int)g[v].size()==2) - ((int)g[v].size()==1);
            ans += (A==B);
            self(self,u,v);
        }
    };
    dfs(dfs,1,0);
    cout<<ans<<"\n";
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t; if(!(cin>>t)) return 0;
    while(t--) solve();
    return 0;
}