Ağac!#12252

Ağac! (Həll təhlili)

Problem Müəllifi:

Timosh

Hazırlayan:

Hasan Saleh (MathModel)

Redaktə edən:

Hasan Saleh (MathModel)

Həll

Bir düyünü yarpaq adlandırırıq əgər onun dərəcəsi -dirsə. ağacdakı yarpaqların ümumi sayını göstərsin.

Ağacı -də kökləyin. Hər bir düyün üçün, düyünün alt ağacında (bu kök nəzərə alınmaqla) olan yarpaqların sayını göstərsin. -ni bir DFS ilə hesablaya bilərik:

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

Hər hansı bir kənarı nəzərdən keçirin, burada -nin valideynidir. Bu kənarı kəsdikdə iki komponent yaranır:

- -tərəfi yarpağa malikdir, amma -nin dərəcəsi -ə düşür. Bir düyün yarpaq olur əgər onun dərəcəsi idisə, və bir yarpaq yarpaq olmağı dayandırır əgər onun dərəcəsi idisə. Buna görə də, kəsildikdən sonra -tərəfdəki yarpaqların sayı

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

- -tərəfi L-s[v] yarpağa malikdir, və bir kənar itirir, buna görə də onun dərəcəsi də -ə düşür. Beləliklə, kəsildikdən sonra -tərəfdəki yarpaqların sayı

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

Bir kənar balanslıdır əgər A=B. Biz L=s[1]-i birinci DFS-dən hesablaya bilərik, sonra valideyn-uşaq kənarları üzərində ikinci DFS-də yuxarıdakı bərabərliyi yoxlayıb neçə dəfə baş verdiyini sayarıq.

Düzgünlük eskizi

kəsilməsi yalnız ucları və -də yarpaq statusunu dəyişir (digər hər kəs eyni dərəcəni saxlayır), buna görə də +[\deg=2]-[\deg=1] ilə düzəliş etmək həm zəruri, həm də kifayətdir. Çünki və L-s[v] kəsilmədən əvvəl hər tərəfdəki yarpaqları dəqiq sayır, A=B balanslı kənarları dəqiq xarakterizə edir.

Komplekslik hər test üçün (iki DFS keçidi).

#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;
}