Arbre !#12252

Arbre ! (Corrigé)

Auteur du Problème:

Timosh

Préparé par:

Hasan Saleh (MathModel)

Édité par:

Hasan Saleh (MathModel)

Solution

Appelons un nœud une feuille s'il a un degré de . Soit le nombre total de feuilles dans l'arbre.

Racinez l'arbre au niveau . Pour chaque nœud , soit le nombre de feuilles à l'intérieur du sous-arbre de (par rapport à cette racine). Nous pouvons calculer par un DFS :

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

Considérons une arête quelconque où est le parent de . Si nous coupons cette arête, deux composants apparaissent :

- Le côté a feuilles, mais le degré de diminue de . Un nœud devient une feuille si et seulement si son degré était , et une feuille cesse d'être une feuille si et seulement si son degré était . Par conséquent, le nombre de feuilles du côté après la coupure est

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

- Le côté a L-s[v] feuilles, et perd une arête incidente, donc son degré diminue également de . Ainsi, le nombre de feuilles du côté après la coupure est

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

Une arête est équilibrée si et seulement si A=B. Nous pouvons calculer L=s[1] à partir du premier DFS, puis dans un second DFS sur les arêtes parent-enfant, tester l'égalité ci-dessus et compter combien de fois elle est vérifiée.

Esquisse de correction

Couper change le statut de feuille uniquement aux extrémités et (tout le monde garde le même degré), donc ajuster par +[\deg=2]-[\deg=1] est à la fois nécessaire et suffisant. Puisque et L-s[v] comptent les feuilles strictement à l'intérieur de chaque côté avant de considérer les changements de degré des extrémités, A=B caractérise exactement les arêtes équilibrées.

Complexité par test (deux traversées 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;
}