During the chemistry lesson Andrew learned that the saturated hydrocarbons (alkanes) enter into radical chlorination reaction. Andrew is a very curious boy, so he wondered how many different products of the reaction may be forms for a given alkane. He managed to solve the task for small molecules, but for large ones he faced some difficulties and asks you to help.Formally, you are given a tree consisting of n vertices, such that the degree of each vertex doesn't exceed 4. You have to count the number of distinct non-isomorphic trees that can be obtained by adding to this tree one new vertex and one new edge, such that the graph is still the tree and the degree of each vertex doesn't exceed 4.Two trees are isomorphic if there exists a bijection f(v) such that vertices u and v are connected by an edge if and only if vertices f(v) and f(u) are connected by an edge.

The first line of the input contains an integer n (1 ≤ n ≤ 100 000) — the number of vertices in the tree. Then follow n - 1 lines with edges descriptions. Each edge is given by two integers ui and vi (1 ≤ ui, vi ≤ n) — indices of vertices connected by an edge. It's guaranteed that the given graph is a tree and the degree of each vertex doesn't exceed 4.

Print one integer — the answer to the question.

NoteIn the first sample, one can add new vertex to any existing vertex, but the trees we obtain by adding a new vertex to vertices 1, 3 and 4 are isomorphic, thus the answer is 2.In the second sample, one can't add new vertex to the first vertex, as its degree is already equal to four. Trees, obtained by adding a new vertex to vertices 2, 3, 4 and 5 are isomorphic, thus the answer is 1.

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
const int _=1e2;
const int maxn=1e5+_;

struct node
{
	int x,y,next;
}a[2*maxn];int n,len,last[maxn],du[maxn];
void ins(int x,int y)
{
	len++;
	a[len].x=x;a[len].y=y;
	a[len].next=last[x];last[x]=len;
}

map<int,int>f[maxn];
map<map<int,int>,int>mp;int cnt;
int dfs(int x,int fr)
{
	if(f[x].count(fr))return f[x][fr];
	map<int,int> h;
	for(int k=last[x];k;k=a[k].next)
	{
		int y=a[k].y;
		if(y!=fr)
			++h[dfs(y,x)];
	}
	if(!mp.count(h))mp[h]=++cnt;
	f[x][fr]=mp[h];
	return f[x][fr];
}

map<int,int>ans;
int main()
{
	int x,y;
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		ins(x,y),ins(y,x);
		du[x]++,du[y]++;
	}
	dfs(1,0);
	for(int i=1;i<=n;i++)
    	if(du[i]<4)ans[dfs(i,0)]=1;
    printf("%d\n",ans.size());

    return 0;
}

#include<bits/stdc++.h>
#define int long long
using namespace std;
map<pair<int,int>,int> mp;
int n,x,y,a[1000000][2],last[1000000],kk,f[1000000];
int ans,cd[1000000],lsg1,ff[1000000],lsg2;
void doit(int x,int y){a[++kk][0]=last[x];a[kk][1]=y;last[x]=kk;cd[x]++;}
void dfs(int x,int fa){
	f[x]=2333333;ff[x]=23333;for (int i=last[x];i;i=a[i][0])
		if (a[i][1]!=fa){
			dfs(a[i][1],x);(f[x]+=f[a[i][1]]*f[a[i][1]]%lsg1*f[a[i][1]])%=lsg1;
			(ff[x]+=ff[a[i][1]]*ff[a[i][1]]%lsg2*ff[a[i][1]])%=lsg2;
		}
}void dfs1(int x,int fa){
	int kk1=((f[fa]-f[x]*f[x]%lsg1*f[x])%lsg1+lsg1)%lsg1;
	int kk2=((ff[fa]-ff[x]*ff[x]%lsg2*ff[x])%lsg2+lsg2)%lsg2;
	if (x!=1)(f[x]=f[x]+kk1*kk1%lsg1*kk1)%=lsg1,(ff[x]=ff[x]+kk2*kk2%lsg2*kk2)%=lsg2;
	if (!mp[make_pair(f[x],ff[x])]&&cd[x]<4)mp[make_pair(f[x],ff[x])]=1,ans++;
	for (int i=last[x];i;i=a[i][0])
		if (a[i][1]!=fa)dfs1(a[i][1],x);
}
signed main(){
	ios::sync_with_stdio(false);
	cin>>n;lsg1=1e9+7;lsg2=1e9+9;
	for (int i=1;i<n;i++)cin>>x>>y,doit(x,y),doit(y,x);dfs(1,0);dfs1(1,0);
	cout<<ans<<endl;
}

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

const int mod = 1e9+9;
const int MAXN = 1e5 + 10;
const int p = 257;
const int q = 1e9+7;
multiset<int> H[MAXN];
vector<int> g[MAXN];
int n;
int cnt = 0;
map<multiset<int>, int> M;

int add(int a, int b) {
	return (a+b)%mod;
}

int mul(long long a, long long b) {
	return a*b%mod;
}

int hashing(const multiset<int> H) {
	if (not M.count(H))
		M[H] = cnt++;
	return M[H];
}

void dfs(int x, int p) {
	for (int v : g[x]) {
		if (v == p) continue;
		dfs(v, x);
		H[x].insert(hashing(H[v]));
	}
	for (int i = H[x].size(); i < 4; ++i) {
		H[x].insert(mod-1);
	}
}

set<int> Set;
void dfsRoot(int x, int p) {
	if (p) {
		multiset<int> aux = H[p];
		aux.erase(aux.lower_bound(hashing(H[x])));
		aux.insert(mod-1);
		H[x].erase(H[x].lower_bound(mod-1));
		H[x].insert(hashing(aux));
	}
	if (g[x].size() != 4)
		Set.insert(hashing(H[x]));
	for (int v : g[x])
		if (v != p)
			dfsRoot(v, x);
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i < n; ++i) {
		int u, v;
		scanf ("%d %d",  &u, &v);
		g[u].emplace_back(v);
		g[v].emplace_back(u);
	}

	dfs(1, 0);
	dfsRoot(1, 0);
	cout << Set.size() << endl;

	return 0;
}

//============================================================================
// Name        : CodeForces.cpp
// Author      : Ivan
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <iomanip>
#include <sstream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <unordered_set>
#include <unordered_map>

using namespace std;

vector<int> G[100001];
map<vector<int>, int> tmap;
map<pair<int, int>, int> vmap;
int counter = 1;

int getId(vector<int> &c_ids) {
	sort(c_ids.begin(), c_ids.end());
	int &id = tmap[c_ids];
	if (id == 0) id = counter++;
	return id;
}

int dfsBuildId(int v, int par) {
	int &id = vmap[make_pair(v, par)];
	if (id != 0) return id;
	vector<int> c_ids;
	for (int child : G[v]) {
		if (child == par) continue;
		int c_id = dfsBuildId(child, v);
		c_ids.push_back(c_id);
	}
	id = getId(c_ids);
	return id;
}

void B() {
	int n, x, y;
	cin >> n;
	for (int i=1; i<n; i++) {
		cin >> x >> y;
		G[x].push_back(y);
		G[y].push_back(x);
	}
	unordered_set<int> isom;
	for (int i=1; i<=n; i++) {
		if (G[i].size() < 4)
			isom.insert(dfsBuildId(i, 0));
	}
	cout << isom.size() << endl;
}

int main() {
	B();
}

#include<bits/stdc++.h>
using namespace std;
const int N=100001;
map<int,int>mp[N];
map<vector<int>,int>H;
set<int>S;
vector<int>e[N];
int n,i,x,y,tot;
inline char gc(){
	static char buf[100000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd(){
	int x=0,fl=1;char ch=gc();
	for (;ch<48||ch>57;ch=gc())if(ch=='-')fl=-1;
	for (;48<=ch&&ch<=57;ch=gc())x=(x<<3)+(x<<1)+(ch^48);
	return x*fl;
}
inline void wri(int a){if(a<0)a=-a,putchar('-');if(a>=10)wri(a/10);putchar(a%10|48);}
inline void wln(int a){wri(a);puts("");}
int dfs(int u,int fa){
	vector<int>cnt;
	if (mp[u][fa]) return mp[u][fa];
	for (int i=0,v;i<e[u].size();i++)
		if ((v=e[u][i])!=fa) cnt.push_back(dfs(v,u));
	sort(cnt.begin(),cnt.end());
	if (!H[cnt]) H[cnt]=++tot;
	return mp[u][fa]=H[cnt];
}
int main(){
	n=rd();
	for (i=1;i<n;i++) x=rd(),y=rd(),e[x].push_back(y),e[y].push_back(x);
	for (i=1;i<=n;i++)
		if (e[i].size()<4) S.insert(dfs(i,0));
	printf("%d",S.size());
}

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
inline char gc(){
	static char buf[1<<14],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++;
}
#define dd c=gc()
inline ll read(){
	ll x=0,f=1;char dd;
	for(;!isdigit(c);dd){if(c=='-')f=-1;if(c==EOF)return EOF;}
	for(;isdigit(c);dd)x=(x<<1)+(x<<3)+(c^48);return x*f;
}
#undef dd
inline void write(ll x){
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);putchar(x%10|48);
}
const ll N=1e5+10,P1=9376841,P2=9376897,INF=951299;
ll head[N],edge,n,ins[N],ans;
struct edge{ll to,net;}e[N<<1];
struct Ha{
	ll t1,t2;
	Ha(ll _t1=INF,ll _t2=INF):t1(_t1),t2(_t2){}
	bool operator <(const Ha& x)const{
		return t1==x.t1?t2<x.t2:t1<x.t1;
	}
	Ha operator +(const Ha& x)const{
		return Ha((t1+x.t1)%P1,(t2+x.t2)%P2);
	}
	Ha operator *(const Ha& x)const{
		return Ha(t1*x.t1%P1,t2*x.t2%P2);
	}
};
set<Ha>s;
map<ll,Ha>vis[N];
inline void addedge(ll x,ll y){
	e[++edge].to=y,e[edge].net=head[x],head[x]=edge;
	e[++edge].to=x,e[edge].net=head[y],head[y]=edge;
	++ins[x],++ins[y];
}
inline Ha dfs(ll x,ll fa){
	if (vis[x].find(fa)!=vis[x].end()) return vis[x][fa];
	Ha ret;
	for (ll i=head[x];i;i=e[i].net)
		if (e[i].to!=fa){
			Ha t=dfs(e[i].to,x);
			ret=ret+t*t*t;
		}
	return vis[x][fa]=ret;
}
int main(){
	n=read();
	for (ll i=1;i<n;++i) addedge(read(),read());
	for (ll i=1;i<=n;++i)
		if (ins[i]!=4){
			Ha tem=dfs(i,0);
			if (s.find(tem)==s.end()) ++ans,s.insert(tem);
		}
	write(ans);
	return 0;
}

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
struct Edge{
	int v,nxt;
}e[200010];int tot;
int deg[100010];
int first[100010];
void build(int u,int v)
{
	e[++tot]=(Edge){v,first[u]};
	first[u]=tot;deg[u]++;
	return ;
}
int siz[100010];
int mxsiz[100010];
int f[100010];
const int Mod=1000000007;
const int M=10007;
int h[100010];
void dfs(int u,int lst)
{
	siz[u]=1;mxsiz[u]=0;
	for(int i=first[u];i;i=e[i].nxt)
		if(e[i].v!=lst){
			dfs(e[i].v,u);siz[u]+=siz[e[i].v];
			mxsiz[u]=max(mxsiz[u],siz[e[i].v]);
		}
	return ;
}
void solve(int u,int lst)
{
	h[u]=1;f[u]=(deg[u]<4);
	vector<pair<int,int> >val;
	for(int i=first[u];i;i=e[i].nxt)
		if(e[i].v!=lst){
			solve(e[i].v,u);
			val.push_back(make_pair(h[e[i].v],f[e[i].v]));
		}
	sort(val.begin(),val.end());
	int pre=Mod+1;
	for(int i=0;i<val.size();i++)
	{
		int H=val[i].first,F=val[i].second;
		h[u]=((1ll*h[u]*M%Mod*H%Mod)^H)%Mod;
		if(H!=pre){
			pre=H;
			f[u]+=F;
		}
	}
	return ;
}
int main()
{
	int n;scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d %d",&u,&v);
		build(u,v);
		build(v,u);
	}
	dfs(1,0);
	int S=0,T=0;
	for(int i=1;i<=n;i++)
		if(max(mxsiz[i],n-siz[i])<=n/2)
		{
			T=S;
			S=i;
		}
	if(T){
		solve(S,T);
		solve(T,S);
		if(h[S]!=h[T])printf("%d\n",f[S]+f[T]);
		else printf("%d\n",f[S]);
	}
	else{
		solve(S,0);
		printf("%d\n",f[S]);
	}
	return 0;
}

#include <bits/stdc++.h>

typedef long long ll;
typedef long long llong;
typedef long double ld;
typedef unsigned long long ull;

using namespace std;

mt19937_64 rnd(123);
const int MAXN = 120000;
const ll MOD = 100000000000000003ll;
int was[MAXN];
int sz[MAXN];
int p[MAXN];
vector<int> eds[MAXN];
int n;

void dfs1(int v) {
	was[v] = 1;
	sz[v] = 1;
	for (int u: eds[v]) {
		if (!was[u]) {
			p[u] = v;
			dfs1(u);
			sz[v] += sz[u];
		}
	}
}

ll mul(ll a, ll b) {
	ll q = ll(ld(a) * ld(b) / ld(MOD));
	ll r = a * b - q * MOD;
	return (r + 6 * MOD) % MOD;
}

struct hsh {
	ll a;
	hsh(ll x = 0) {
		a = x % MOD;
	}
	hsh operator+(hsh x) {
		return hsh(a + x.a);
	}
	hsh operator-(hsh x) {
		return hsh(a - x.a + MOD);
	}
	hsh operator*(hsh x) {
		return mul(a, x.a);
	}
};

bool operator<(hsh a, hsh b) {
	return a.a < b.a;
}

hsh rn[MAXN];

hsh pw(hsh a, ll b) {
	hsh ans = 1; while (b) {
		while (!(b & 1)) b >>= 1, a = (a * a);
		ans = (ans * a), --b;
	} return ans;
}

hsh bck(hsh x) {
	assert(x.a != 0);
	return pw(x, MOD - 2);
}

struct st {
	set<hsh> *ss;
	hsh df;
	hsh ml;
	hsh ad;
	st() {
		ss = new set<hsh>;
		df = 0;
		ad = 0;
		ml = 1;
	}
};

st merge(st a, st b) {
	if (a.ss->size() < b.ss->size())
		swap(a, b);
	hsh d1 = (a.df * a.ml) + a.ad;
	hsh d2 = (b.df * b.ml) + b.ad;
	a.ml = a.ml * d2;
	a.ad = a.ad * d2;
	b.ml = b.ml * d1;
	b.ad = b.ad * d1;
	hsh bc = bck(a.ml);
	for (auto x: *b.ss) {
		x = x * b.ml + b.ad;
		x = (x - a.ad) * bc;
		a.ss->insert(x);
	}
	return a;
}

st dfs2(int v, int h) {
	was[v] = 1;
	st now;
	now.df = 1;
	if (eds[v].size() < 4)
		now.ss->insert(hsh(rn[h] + 1));
	for (int u: eds[v]) {
		if (was[u])
			continue;
		st tmp = dfs2(u, h + 1);
		tmp.ad = tmp.ad + rn[h];
		now = merge(now, tmp);
	}

	return now;
}

int gfl = 0;
int main() {
	scanf("%d", &n);
	for (int i = 0; i < n - 1; ++i) {
		int a, b;
		scanf("%d%d", &a, &b);
		--a, --b;
		eds[a].push_back(b);
		eds[b].push_back(a);
	}
	dfs1(0);
	int bst = -1;
	for (int i = 0; i < n; ++i)
		if (sz[i] * 2 >= n && (bst == -1 || sz[i] < sz[bst]))
			bst = i;
	if (sz[bst] * 2 == n) {
		int a = bst;
		int b = p[a];
		for (int i = 0; i < eds[a].size(); ++i) {
			if (eds[a][i] == b) {
				eds[a].erase(eds[a].begin() + i);
				break;
			}
		}
		for (int i = 0; i < eds[b].size(); ++i) {
			if (eds[b][i] == a) {
				eds[b].erase(eds[b].begin() + i);
				break;
			}
		}
		eds[a].push_back(n);
		eds[b].push_back(n);
		eds[n].push_back(a);
		eds[n].push_back(b);
		++n;
		gfl = 1;
		bst = n - 1;
	}
	memset(was, 0, sizeof(was));
	for (int i = 0; i < n; ++i) {
		rn[i] = hsh(rnd() % MOD);
	}
	int ans = dfs2(bst, 0).ss->size() - gfl;
	cout << ans << "\n";
	return 0;
}

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
#define int long long
using namespace std;
inline int read()
{
    char c=getchar();int x=0;bool f=0;
    for(;!isdigit(c);c=getchar())f^=!(c^45);
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);
    if(f)x=-x;return x;
}
#define maxn 100005
int n,cnt,d[maxn];
map<int,int>f[maxn];
map<vector<int>,int>h;
set<int>s;
struct edge{
	int to,nxt;
}e[maxn<<1];
int tot,head[maxn];
inline void adde(int u,int v){
	e[++tot]=(edge){v,head[u]};
	head[u]=tot;
}
inline int ID(vector<int>v){
	if(!h[v])h[v]=++cnt;
	return h[v];
}

int dfs(int u,int fa)
{
	if(f[u][fa])return f[u][fa];
	vector<int>g;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v!=fa)g.push_back(dfs(v,u));
	}
	sort(g.begin(),g.end());
	return f[u][fa]=ID(g);
}
signed main()
{
	n=read();
	For(i,2,n){
		int u=read(),v=read();
		adde(u,v);adde(v,u);
		d[u]++,d[v]++;
	}
	For(i,1,n)if(d[i]<4)s.insert(dfs(i,0));
	cout<<s.size();
	return 0;
}

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define _for(i, a, b) for (register int i = a; i < b; ++i)
#define _rep(i, a, b) for (register int i = a; i <= b; ++i)
const int ri_top = 1e7;
char ri[ri_top + 1], *rich = ri, *rr = ri;
inline void rd() {*(rr = ri + fread(rich = ri, 1, ri_top, stdin)) = 0;}
inline char nch() {if (++rich >= rr) rd(); return *rich;}
inline void read_int(int& x) {while (!isdigit(*rich)) nch(); for (x = *rich - '0'; isdigit(nch()); x = x * 10 + *rich - '0');}
std::vector<int> G[100001];
__gnu_pbds::tree<int, __gnu_pbds::null_type> S;
__gnu_pbds::tree<int, int>dp[100001]; //记忆化
__gnu_pbds::tree<int, int>::iterator it;
__gnu_pbds::tree<std::vector<int>, int>l; //hash映射到id
__gnu_pbds::tree<std::vector<int>, int>::iterator it1;
int cnt;
int dfs(const int& u, const int& fa)
{
    if ((it = dp[u].find(fa)) != dp[u].end()) return it->second; //记忆化
    std::vector<int> V;
    for (auto i : G[u]) if (i != fa) V.push_back(dfs(i, u));
    std::sort(V.begin(), V.end()); //将子树的hash值拼接起来并排序
    return dp[u][fa] = (((it1 = l.find(V)) != l.end()) ? it1->second : (l[V] = ++cnt)); //判断是否需要新建一个映射并返回
}
int n, u, v;
int main()
{
    read_int(n);
    _for(i, 1, n) {read_int(u); read_int(v); G[u].push_back(v); G[v].push_back(u);}
    _rep(i, 1, n) if (G[i].size() < 4) S.insert(dfs(i, 0)); //不能忽略对度数的判断. 只有连有氢原子的碳原子才可以被取代(仿佛不能说碳原子被取代那就是不能作为根)
    printf("%d\n", S.size()); //不同的hash值的个数.
}

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#define MAXN 100005
using namespace std;
using namespace __gnu_pbds;

const int ri_top = 1e7;
char ri[ri_top + 1], *rich = ri, *rr = ri;
inline void rd() {*(rr = ri + fread(rich = ri, 1, ri_top, stdin)) = 0;}
inline char nch()
{
	if (++rich >= rr)
		rd();
	return *rich;
}
vector<int> G[MAXN];
tree<int, null_type> S;
tree<int, int>dp[100001];
tree<int, int>::iterator it;
tree<vector<int>, int>l;
tree<vector<int>, int>::iterator it1;
int cnt;
int dfs(const int& u, const int& fa)
{
    if ((it = dp[u].find(fa)) != dp[u].end()) return it->second;
    vector<int> V;
    for (auto i : G[u])
	if (i != fa)
		V.push_back(dfs(i, u));
    sort(V.begin(), V.end());
    return dp[u][fa] = (((it1 = l.find(V)) != l.end()) ? it1->second : (l[V] = ++cnt));
}
int n, u, v;
int main()
{
	cin >> n;
    for(int i = 1; i < n; i ++)
	{
		cin >> u;
		cin >> v;
		G[u].push_back(v);
		G[v].push_back(u);
	}

    for(int i = 1; i <= n; i ++)
		 if (G[i].size() < 4)
		 	S.insert(dfs(i, 0));
	cout<<S.size();
}

#include<bits/stdc++.h>
using namespace std;
#define lp(i,l,r)for(auto i=l;i<=r;++i)
#define rp(i,r,l)for(auto i=r;i>=l;--i)

#include<bits/stdc++.h>
using namespace std;
struct TreeHashing{
	int n,p,d2;
	vector<int>hu,hd,sz;
	vector<vector<int>>adj;
	vector<long long>pw,hash;
	TreeHashing(int _n):
		n(_n),pw(2*n),hu(n+1),hd(n+1),sz(n+1,1),
		d2(0),adj(n+1),hash(n+1),p(1e9+7){
	}
	void add(int u,int v){
		adj[u].push_back(v);
		adj[v].push_back(u);
	}
	void down(int u,int d1=0,int f=0){
		vector<pair<int,int>>t;
		for(int v:adj[u])
			if(v!=f){
				down(v,d1,u);
				if(!d2)
					sz[u]+=sz[v]*(1-d1);
				t.push_back(make_pair(sz[v]*2,hd[v]));
			}
		if(d1*f)
			t.push_back(make_pair((n-sz[u])*2,hu[u]));
		sort(t.begin(),t.end());
		int l=1,&s=d1?*((int*)&hash[u]+d2):(hd[u]=0);
		for(auto i:t){
			s=(s+pw[l]*i.second)%p;
			l+=i.first;
		}
		s=(s+pw[l])%p;
	}
	void up(int u,int f=0){
		int l=0,sl=0,sr=1;
		vector<pair<pair<int,int>,int>>t;
		if(f)
			t.push_back(make_pair(make_pair((n-sz[u])*2,hu[u]),0));
		for(int i=0;i<adj[u].size();++i)
			if(adj[u][i]!=f){
				int v=adj[u][i];
				t.push_back(make_pair(make_pair(sz[v]*2,hd[v]),v));
			}
		sort(t.begin(),t.end());
		for(auto i:t){
			sl=(sl+i.first.second*pw[l])%p;
			l+=i.first.first;
		}
		for(int i=int(t.size()-1);i>=0;--i){
			sl=(sl-t[i].first.second*pw[l-=t[i].first.first]%p+p)%p;
			if(i+1<t.size())
				sr=(sr*pw[t[i+1].first.first]+t[i+1].first.second)%p;
			if(t[i].second)
				hu[t[i].second]=(sl+sr*pw[l])*pw[1]%p;
		}
		for(int v:adj[u])
			if(v!=f)
				up(v,u);
	}
	void run(){
		pw[0]=1;
		for(int i=1;i<2*n;++i)
			pw[i]=pw[i-1]*2%p;
		down(1),up(1),down(1,1);
		d2=1,p=1e9+9;
		for(int i=1;i<2*n;++i)
			pw[i]=pw[i-1]*7%p;
		down(1),up(1),down(1,1);
	}
};
pair<int,int>yy[200010];
void p1(int u){
	cout<<yy[u].first<<" "<<yy[u].second<<endl;
}
void p2(int u,TreeHashing&hs){
	lp(i,0,int(hs.adj[u].size()-1)){
		int v=hs.adj[u][i];
	}
}
int main(){
	ios::sync_with_stdio(0);
	int n;cin>>n;
	TreeHashing th(n);
	vector<int>d(n+1);
	lp(i,1,n-1){
		int u,v;
		cin>>u>>v;
		++d[u],++d[v];
		th.add(u,v);
	}
	th.run();
	set< long long >s;
	lp(i,1,n)if(d[i]<4){

		s.insert(th.hash[i]);
	}
	// lp(i,1,n)
	//if(make_pair(th.hash[i][0],th.hash[i][1])==make_pair(th.hash[42049][0],th.hash[42049][1]))
	//cout<<i<<endl;
	cout<<s.size()<<endl;
	#ifndef ONLINE_JUDGE
	//for(;;);
	#endif
	int u1=42049;
	int u2=43963;
	//p1(u1),p1(u2);
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
const int N = 100020;
int n , cnt;
vector < int > e[N];
map < int , int > f[N];
map < multiset<int> , int > List;
set < int > S;
inline int dp(int x,int fa)
{
    if ( f[x].count(fa) ) return f[x][fa];
    multiset < int > temp;
    for ( int i = 0; i < e[x].size(); i++ )
    {
        int y = e[x][i];
        if ( y == fa ) continue;
        temp.insert( dp( y , x ) );
    }
    if ( !List.count( temp ) ) List[ temp ] = ++cnt;
    return f[x][fa] = List[ temp ];
}
int main(void)
{
    scanf("%d",&n);
    for ( int i = 1; i < n; i++ )
    {
        int u , v;
        scanf("%d%d",&u,&v);
        e[u].push_back( v );
        e[v].push_back( u );
    }
    for ( int i = 1; i <= n; i++ )
        if ( e[i].size() < 4 )
            S.insert( dp( i , 0 ) );
    printf("%d\n",S.size());
    return 0;
}

#include <bits/stdc++.h>
#define FOR(i, j, k) for (int i = j; i <= k; i ++)
#define FORD(i, j, k) for (int i = j; i >= k; i --)
#define mn 100005
#define maxC 1000000007
#define pb push_back
#define F first
#define S second
#define mp make_pair

using namespace std;
int n, r = 0, a[mn], b[mn];
vector<int> g[mn];
map< vector<int> , int > Map;
map<int, int> mark;

int reform(vector<int>& vec)
{
    while(int(vec.size()) < 4)
        vec.pb(-1);
    sort(vec.begin(), vec.end());
    if (Map[vec] == 0)
        Map[vec] = ++ r;
    return Map[vec];
}

void dfs(int u, int p)
{
    vector<int> child = vector<int>();
    FOR(i, 0, int(g[u].size()) - 1)
    {
        int v = g[u][i];
        if (v == p)
            continue;
        dfs(v, u);
        child.pb(a[v]);
    }
    a[u] = reform(child);
    //cout << u << ' ' << a[u] << '\n';
}

void dfs2(int u, int p, int up)
{
    vector<int> child = vector<int>();
    FOR(i, 0, int(g[u].size()) - 1)
    {
        int v = g[u][i];
        if (v == p)
            continue;
        child.pb(a[v]);
        vector<int> type = vector<int>();
        FOR(j, 0, int(g[u].size()) - 1)
        if (j != i && g[u][j] != p)
            type.pb(a[g[u][j]]);
        type.pb(up);
        int t = reform(type);
        //cout << u << " check " << v << ' ' << t << '\n';
        dfs2(v, u, t);
    }
    child.pb(up);
    b[u] = reform(child);
    //cout << u << ' ' << b[u] << '\n';
}

void setup()
{
    cin >> n;
    int u, v;
    FOR(i, 2, n)
    {
        cin >> u >> v;
        g[u].pb(v);
        g[v].pb(u);
    }
    dfs(1, 0);
    dfs2(1, 0, -1);
    int ans = 0;
    FOR(i, 1, n)
        if (int(g[i].size()) < 4 && !mark[b[i]])
            mark[b[i]] = 1, ans ++;
    cout << ans;
}

void xuly()
{

}

int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    setup ();
    xuly ();
    return 0;
}

#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;

const int maxn = 1e5 + 10;
typedef long long ull;
typedef int arr[maxn<<2];
typedef ull prr[maxn<<2][2];
typedef pair<ull, ull> pii;
const ull base = 4000037, mod[2] = {(ull)1e9 + 7, 100001053};

int edg, vsz, n;
prr hsh, pmd = {{1,1}};
arr vedg, frm, to, nxt, last, deg, sz;
pii vec[maxn<<2];

inline void add_mod(ull &x, ull y, ull z, ull mod) {
	x += (y * z) % mod;
	if (x > mod) x -= mod;
}
void add_edge(int u, int v) {
	frm[++edg] = u, to[edg] = v, nxt[edg] = last[u], last[u] = edg;
	frm[++edg] = v, to[edg] = u, nxt[edg] = last[v], last[v] = edg;
	deg[u]++, deg[v]++;
}

void dfs(int x) {
	vedg[x] = 1;
	pii px[2][6] = {};
	int psz[2] = {};
	for (int i = last[to[x]]; i; i = nxt[i])
		if (to[i] != frm[x]) {
			if (!vedg[i]) dfs(i);
			for (int j = 0; j <= 1; ++j)
				px[j][++psz[j]] = pii(hsh[i][j], (ull)sz[i]);
			sz[x] += sz[i];
		}
	for (int j = 0; j <= 1; ++j)
		sort(px[j]+1, px[j]+psz[j]+1);

	for (int j = 0; j <= 1; ++j)
		for (int i = 1; i <= psz[j]; ++i)
			add_mod(hsh[x][j], px[j][i].fi, pmd[px[j][i].se+1][j], mod[j]);
	hsh[x][0]++, hsh[x][1]++;
	sz[x]++;
}
int main() {
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	ios::sync_with_stdio(0);

	cin >> n;
	for (int i = 1; i <= n+1; ++i)
		for (int j = 0; j <= 1; ++j)
			add_mod(pmd[i][j], pmd[i-1][j], base, mod[j]);

	for (int i = 1, u, v; i < n; ++i)
		cin >> u >> v, add_edge(u, v);

	for (int i = 1; i <= edg; ++i)
		if (!vedg[i])
			dfs(i);

	for (int x = 1; x <= n; ++x)
		if (deg[x] <= 3) {
			pii px[2][6];
			int psz[2] = {0,0};
			ull phsh[2] = {0,0};
			for (int i = last[x]; i; i = nxt[i])
				for (int j = 0; j <= 1; ++j)
					px[j][++psz[j]] = pii(hsh[i][j], sz[i]);
			for (int j = 0; j <= 1; ++j)
				sort(px[j]+1, px[j]+psz[j]+1);
			for (int j = 0; j <= 1; ++j)
				for (int i = 1; i <= psz[j]; ++i)
					add_mod(phsh[j], px[j][i].fi, pmd[px[j][i].se][j], mod[j]);
			vec[++vsz] = pii(phsh[0], phsh[1]);
		}

	sort(vec+1, vec+vsz+1);
	cout << (unique(vec+1, vec+vsz+1) - vec - 1);
}

#include <bits/stdc++.h>
using namespace std;
const int N = 100020;
int n , cnt;
vector < int > e[N];
map < int , int > f[N];
map < vector<int> , int > List;
set < int > S;
inline int dp(int x,int fa)
{
    if ( f[x].count(fa) ) return f[x][fa];
    vector < int > temp;
    for ( int i = 0; i < e[x].size(); i++ )
    {
        int y = e[x][i];
        if ( y == fa ) continue;
        temp.push_back( dp( y , x ) );
    }
    sort( temp.begin() , temp.end() );
    if ( !List.count( temp ) ) List[ temp ] = ++cnt;
    return f[x][fa] = List[ temp ];
}
int main(void)
{
    scanf("%d",&n);
    for ( int i = 1; i < n; i++ )
    {
        int u , v;
        scanf("%d%d",&u,&v);
        e[u].push_back( v );
        e[v].push_back( u );
    }
    for ( int i = 1; i <= n; i++ )
        if ( e[i].size() < 4 )
            S.insert( dp( i , 0 ) );
    printf("%d\n",S.size());
    return 0;
}

#include<bits/stdc++.h>
#define int long long
#define N 100010
#define V (to[i])
using namespace std;
namespace program
{
	int tot=0,Next[N<<1],to[N<<1],head[N<<1],from[N<<1];
	int in1[N<<1],n;
	int Mod1=998244353,Mod2=1000000007;
	struct node
	{
		int T1,T2;
	};
	bool operator <(node a,node b)
	{
		if(a.T1!=b.T1)
		{
			return a.T1<b.T1;
		}
		else
		{
			return a.T2<b.T2;
		}
	}
	map<node,bool>flag;
	typedef pair<int,int> P;
	map<P,bool> limit1;
	map<P,node> limit2;
	inline void add(int x,int y)
	{
		tot+=1;
		Next[tot]=head[x];
		from[tot]=x;
		to[tot]=y;
		head[x]=tot;
	}
	inline node dfs(int x,int fa)
	{
		if(limit1[P(x,fa)])
		{
			return limit2[P(x,fa)];
		}
		node ans;
		ans.T1=ans.T2=1;
		for(int i=head[x];i;i=Next[i])
		{
			if(V==fa)
			{
				continue;
			}
			node oo=dfs(V,x);
			oo.T1=oo.T1%Mod1*oo.T1%Mod1*oo.T1%Mod1*oo.T1%Mod1*oo.T1%Mod1;
			oo.T2=oo.T2%Mod2*oo.T2%Mod2*oo.T2%Mod2*oo.T2%Mod2*oo.T2%Mod2;
			ans.T1=(ans.T1+oo.T1)%Mod1;
			ans.T2=(ans.T2+oo.T2)%Mod2;
		}
		limit2[P(x,fa)]=ans;
		limit1[P(x,fa)]=1;
		return ans;
	}
	inline void work()
	{
		cin>>n;
		for(int i=1,x,y;i<n;i++)
		{
			cin>>x>>y;
			add(x,y);
			add(y,x);
			in1[x]+=1;
			in1[y]+=1;
		}
		int res=0;
		for(int i=1;i<=n;i++)
		{
			if(in1[i]!=4)
			{
				node oo=dfs(i,0);
				if(!flag[oo])
				{
					res+=1;
					flag[oo]=1;
				}
			}
		}
		cout<<res<<endl;
	}
}
signed main()
{
	program::work();
	return 0;
}

#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
const int N=1e5+5;
struct edge{
	int link,next;
}e[N<<1];
int tot,n,ok[N*5],head[N],cnt,deg[N];
inline int read(){int x=0,f=1,ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}
inline void write(int x){if (x<0) putchar('-'),x=-x; if (x>=10) write(x/10); putchar(x%10+'0');}
inline void writeln(int x){write(x); puts("");}
inline void add_edge(int u,int v){
	e[++tot]=(edge){v,head[u]}; head[u]=tot;
}
inline void insert(int u,int v){
	add_edge(u,v); add_edge(v,u);
	deg[u]++; deg[v]++;
}
inline void init(){
	n=read();
	for (int i=1;i<n;i++){
		int u=read(),v=read();
		insert(u,v);
	}
}
map<vector<int >,int >mp;
map<int ,int >dp[N];
int dfs(int u,int fa){
	if (dp[u][fa]) return dp[u][fa];
	vector<int> vec;
	for (int i=head[u];i;i=e[i].next){
		int v=e[i].link;
		if (v!=fa){
			vec.push_back(dfs(v,u));
		}
	}
	sort(vec.begin(),vec.end());
	if (!mp[vec]) mp[vec]=++cnt;
	return dp[u][fa]=mp[vec];
}
inline void solve(){
	for (int i=1;i<=n;i++){
		if (deg[i]<4) {
			ok[dfs(i,0)]=1;
		}
	}
	int ans=0;
	for (int i=1;i<=cnt;i++) ans+=ok[i];
	writeln(ans);
}
int main(){
	init(); solve();
	return 0;
}

#include<bits/stdc++.h>
#define mii map<int,int>
using namespace std;
int n, cnt, u, v, deg[101000];
map<mii,int>mp;
mii f[101000], ans, G[101000];

int dfs(int x,int fff){
  if (f[x].count(fff)) return f[x][fff];
  mii v;
  for (auto y:G[x])
    if (y.first!=fff)
      ++v[dfs(y.first,x)];
  if (!mp.count(v)) mp[v]=++cnt;
  return f[x][fff]=mp[v];
}

int main(){
  cin>>n;
  for (int i=n;--i;){
    cin>>u>>v; ++deg[u],++deg[v];
    G[u][v],G[v][u];
  }
  for (int i=1;i<=n;++i)
    if (deg[i]<4)
      ans[dfs(i,0)]=1;
  cout<<ans.size();
}

# include <vector>
# include <cstring>
# include <map>
# include <set>
# include <algorithm>
# include <vector>

using namespace std;

map< vector<int> , int > hs;

const int maxn = 100010;
int dep[maxn];
vector<int> G[maxn];

int Id(vector<int> vec) {
	static int cnt = 0;
	sort(vec.begin(), vec.end());
	if(hs.count(vec) == 0)
		hs[vec] = cnt++;
	return hs[vec];
}

int f[maxn][2];
int get(int u,int v) {
	int &val = f[dep[u] > dep[v] ? u : v][dep[u] > dep[v]];
	if(val != -1) return val;
	vector<int> vec;
	for (auto p: G[u]) if(p != v) vec.push_back(get(p, u));
	return val = Id(vec);
}

void dfs(int u,int par) {
	dep[u] = dep[par] + 1;
	for(auto v: G[u]) if(v != par) dfs(v, u);
}

int main() {
	int n; scanf("%d", &n);
	for(int i = 1; i < n; ++i) {
		int x, y; scanf("%d%d", &x, &y);
		G[x].push_back(y);
		G[y].push_back(x);
	}
	dfs(1, 1);
	vector<int> vec;
	int val = Id(vec);
	memset(f, -1, sizeof(f));
	set<int> S;
	for(int i = 1; i <= n; ++i) {
		if(G[i].size() < 4) {
			vec.clear();
			vec.push_back(val);
			for(auto u: G[i])
				vec.push_back(get(u, i));
			S.insert(Id(vec));
		}
	}
	printf("%d\n", (int)S.size());
	return 0;
}

#include <map>
#include <vector>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxn = 100001;
int n, tot, deg[maxn], ans, seq[maxn];
vector<int> e[maxn];
map<vector<int>, int> idx;
map<pair<int, int>, int> Hash;
int getID(const vector<int> &src)
{
	return !idx.count(src) ? idx[src] = ++tot : idx[src];
}
int dfs(int u, int fa)
{
	pair<int, int> cur = make_pair(u, fa);
	if(Hash.count(cur))
		return Hash[cur];
	vector<int> nxt;
	for(vector<int>::iterator it = e[u].begin(); it != e[u].end(); ++it)
		if(*it != fa)
			nxt.push_back(dfs(*it, u));
	sort(nxt.begin(), nxt.end());
	return Hash[cur] = getID(nxt);
}
int main()
{
	scanf("%d", &n);
	for(int i = 1; i < n; ++i)
	{
		int u, v;
		scanf("%d%d", &u, &v);
		++deg[u];
		++deg[v];
		e[u].push_back(v);
		e[v].push_back(u);
	}
	for(int i = 1; i <= n; ++i)
		if(deg[i] < 4)
			seq[ans++] = dfs(i, -1);
	sort(seq, seq + ans);
	ans = unique(seq, seq + ans) - seq;
	printf("%d\n", ans);
	return 0;
}

#include<cstdio>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
using namespace std;
int n,cnt;
int ans[100005];
vector<int>e[100005];
map<int,int> mp[100005];
map<vector<int>,int> H;
set<int> st;
int dp(int x,int fa)
{
  if(mp[x][fa])return mp[x][fa];
  vector<int> cur;
  for(int i=0;i<e[x].size();i++)
    if(e[x][i]!=fa)
      cur.push_back(dp(e[x][i],x));
  sort(cur.begin(),cur.end());
  if(!H[cur])H[cur]=++cnt;
  return mp[x][fa]=H[cur];
}
int main(){
  scanf("%d",&n);
  for(int i=1;i<n;i++){
    int u,v;scanf("%d%d",&u,&v);
    e[u].push_back(v);
    e[v].push_back(u);
  }
  for(int i=1;i<=n;i++)
    if(e[i].size()<4)
      st.insert(dp(i,0));
  printf("%d\n",st.size());
  return 0;
}

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

typedef unsigned long long ull;
const int maxn = 1e5+10;
const ull p = 1e8+7;
const ull B = 1e9+7;
ull hs[maxn], hs1[maxn];
int dp[maxn];
int n;

vector<int> G[maxn];

void init()
{
    for(int i = 1; i <= n; ++ i) G[i].clear();
}

void AddEdge(int a, int b)
{
    G[a].push_back(b);
}

int d[maxn];

int getd(int s)
{
    int root = s;
    queue<int> Q;
    Q.push(s);
    memset(d, -1, sizeof(d));
    d[s] = 0;
    while(Q.size())
    {
        int u = Q.front();
        Q.pop();
        if(d[u] > d[root]) root = u;
        for(int i = 0; i < G[u].size(); ++ i)
        {
            int t = G[u][i];
            if(~d[t]) continue;
            else
            {
                d[t] = d[u] + 1;
                Q.push(t);
            }
        }
    }
    return root;
}

int a, b, maxd;

int getmid(int s, int fa, int d)
{
    int dd = d;
    for(int i = 0; i < G[s].size(); ++ i)
    {
        int t = G[s][i];
        if(t == fa) continue;
        int tmp = getmid(t, s, d+1);
        if(d == maxd/2 && tmp == maxd)
        {
            if(maxd&1)
            {
                a = s, b = t;
            }
            else a = s;
        }
        dd = max(dd, tmp);
    }
    return dd;
}

bool cmp(int a, int b)
{
    if(hs[a] != hs[b]) return hs[a] > hs[b];
    return dp[a] > dp[b];
}

void dfs(int s, int fa)
{
    hs[s] = p;
//    hs1[s] = B;
    dp[s] = 0;
    if(G[s].size() < 4) dp[s] ++;
    for(int i = 0; i < G[s].size(); ++ i)
    {
        int t = G[s][i];
        if(t == fa) continue;
        dfs(t, s);
    }
    sort(G[s].begin(), G[s].end(), cmp);
    for(int i = 0; i < G[s].size(); ++ i)
    {
        int t = G[s][i];
        if(t == fa) continue;
        hs[s] = hs[s]*dp[t]*B + hs[t]*dp[t];
//        hs1[s] = hs1[s]*p + hs1[t];
        dp[s] += dp[t];
        for(int j = 0; j < i; ++ j)
        {
            int tt = G[s][j];
            if(tt == fa) continue;
            if(hs[t] == hs[tt] && dp[t] == dp[tt])
            {
                dp[s] -= dp[t];
                break;
            }
        }
    }
}

int main()
{
    while(~scanf("%d", &n))
    {
        init();
        for(int i = 1; i < n; ++ i)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            AddEdge(a, b);
            AddEdge(b, a);
        }
        int rt = getd(1);
        maxd = d[getd(rt)];
        getmid(rt, -1, 0);
        if(maxd&1)
        {
            AddEdge(0, a), AddEdge(0, b);
            rt = 0;
            for(int i = 0; i < G[a].size(); ++ i)
            {
                if(G[a][i] == b) G[a][i] = 0;
            }
            for(int i = 0; i < G[b].size(); ++ i)
            {
                if(G[b][i] == a) G[b][i] = 0;
            }
        }
        else
        {
            rt = a;
        }
        dfs(rt, -1);
        printf("%d\n", dp[rt]-(maxd&1));
    }
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 200005;
int n , pre[N] , mcnt;
struct edge {
    int x , next;
} e[N << 1];

int deg[N];
bool f[N << 1];
int Hash[N << 1];
void addedge(int x , int y) {
    e[mcnt] = (edge) {y , pre[x]} , pre[x] = mcnt ++;
}
map< vector<int> , int> HH;
int id(vector<int> V) {
    if (!HH.count(V)) {
        return HH[V] = HH.size();
    }
    return HH[V];
}

int dfs(int o) {
    if (f[o]) {
        return Hash[o];
    } f[o] = 1;
    int x = e[o].x;
    vector< int > V;
    for (int i = pre[x] ; ~i ; i = e[i].next) {
        int y = e[i].x;
        if ((i ^ o) != 1) {
            V.push_back(dfs(i));
        }
    }
    sort(V.begin() , V.end());
    return Hash[o] = id(V);
}

int main() {
    scanf("%d" , &n);
    memset(pre , -1,  sizeof(pre));
    for (int i = 0 ; i < n - 1 ; ++ i) {
        int x , y;
        scanf("%d%d" , &x , &y);
        addedge(x , y);
        addedge(y , x);
        ++ deg[x];
        ++ deg[y];
    }
    for (int i = 1 ; i <= n ; ++ i) {
        addedge(i + n , i);
    }
    vector<int> res;
    set<int> P;
    for (int i = 1 ; i <= n ; ++ i) {
        if (deg[i] + 1 <= 4) {
            int j = n * 2 + i - 3;
            //printf("%d %d\n" , j , e[j].x);
            P.insert(dfs(j));
            //cout << j << ' ' << dfs(j) << endl;
        }
    }
    cout << P.size() << endl;
}

#include<bits/stdc++.h>
#define mk make_pair
#define pk push_back
using namespace std;
typedef long long LL;
typedef pair<int,int> pi;
template<class T> bool cmax(T &x,T y){return y>x?x=y,1:0;}
template<class T> bool cmin(T &x,T y){return y<x?x=y,1:0;}
const int N=1e5+5;
int n,cnt,du[N];
vector<int> to[N];
map<int,int> mp[N];
map<vector<int>,int> hah;
set<int> ans;
int dp(int x,int pre){
	if(mp[x][pre]) return mp[x][pre];
	vector<int> tmp;
	for(auto y:to[x])if(y^pre)tmp.pk(dp(y,x));
	sort(tmp.begin(),tmp.end());
	if(!hah[tmp]) hah[tmp]=++cnt;
	return mp[x][pre]=hah[tmp];
}
int main(){
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1,x,y;i<n;++i) cin>>x>>y,to[x].pk(y),to[y].pk(x),++du[x],++du[y];
	for(int i=1;i<=n;++i)if(du[i]<4) ans.insert(dp(i,0));
	cout<<ans.size()<<endl;
	return 0;
}

#include<map>
#include<set>
#include<stack>
#include<cmath>
#include<ctime>
#include<vector>
#include<string>
#include<bitset>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
using namespace std;
const int mod[2]={1000*1000*1000+9,1000*1000*1000+7};
int ex[2][201000],inv[2][201000];
const int base[2]={37,107};
int n,sz[101000],rt[2],num,times,from[101000],to[101000],pr[101000],bw[2][2][101000],now_hs,now_mb[2][101000];
int pm[101000];
bool vis[101000];
struct pp
{
	int id,vl[2],size;
	bool operator <(const pp &temp)const
	{
		if(size==temp.size)
		{
			if(vl[0]==temp.vl[0])
		       return vl[1]<temp.vl[1];
		    return vl[0]<temp.vl[0];
		}
		return size<temp.size;
	}
};
int hs[2][101000];
vector<pp>adj[101000];
set<long long>ha;
int power(int a,int n,int mod)
{
	if(n==0)
	   return 1;
    int ret=power(a,n/2,mod);
    ret=(int)((long long)ret*(long long)ret%mod);
    if(n%2)
       ret=(int)((long long)ret*(long long)a%mod);
    return ret;
}
void get_size(int id,int pa)
{
	int i,j,s,p,q,ip;
	sz[id]=1;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		    continue;
        get_size(ip,id);
	    sz[id]+=sz[ip];
	}
}
void choose_root(int id,int pa,int now_sz,int root[],int &nc)
{
	int ip,i,j,s,p,q,ax=now_sz,sum=now_sz+1,ch;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		    continue;
        if(ax<=sz[ip])
        {
        	ax=sz[ip];
        	ch=ip;
        }
        sum+=sz[ip];
	}
	if(ax*2<=sum)
	{
		root[nc++]=id;
		if(ax*2==sum)
		   root[nc++]=ch;
	}
	else
	    choose_root(ch,id,sum-ax,root,nc);
}
void get_hash(int id,int pa)
{
	int i,j,s,p,q,ip;
	hs[0][id]=hs[1][id]=1;
	sz[id]=1;
	pr[id]=pa;
//	from[id]=times++;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		   continue;
		get_hash(ip,id);
		sz[id]+=sz[ip];
		for(j=0;j<2;j++)
            adj[id][i].vl[j]=hs[j][ip];
        adj[id][i].size=sz[ip];
	}
	sort(adj[id].begin(),adj[id].end());
	int now_sz=1;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		   continue;
		for(j=0;j<2;j++)
		{
		    hs[j][id]+=(int)((long long)ex[j][now_sz]*(long long)adj[id][i].vl[j]%mod[j]);
	    	hs[j][id]%=mod[j];
		}
		now_sz+=2*adj[id][i].size;
	}
	for(j=0;j<2;j++)
	{
	   hs[j][id]+=(ex[j][now_sz]<<1)%mod[j];
	   hs[j][id]%=mod[j];
	}
//	to[id]=times++;
}
void solve(int flag,int id,int mb[])
{
	int i,j,s,p,q,ip,iq,ix,ie,vl,now_hs[2],now_sz,ch;
	pp now,pre,nxt;
	from[id]=times++;
	for(j=0;j<2;j++)
	{
	    now_mb[j][id]=mb[j];
	    mb[j]=(mb[j]+ex[j][from[id]])%mod[j];
	}
	if(adj[id].size()<4)
    {
    	vector<pp>rp;
    	for(j=0;j<2;j++)
              now_hs[j]=(1+ex[j][1]+(ex[j][2]<<1)%mod[j])%mod[j];
         now_sz=3;
         for(i=0;i<adj[id].size();i++)
         {
         	 ip=adj[id][i].id;
         	 if(ip==pr[id])
         	    continue;
    	  //    if(id==1)
    	    //     printf("hs[ip]=%d\n",hs[ip]);
    	     for(j=0;j<2;j++)
      	        now_hs[j]=(now_hs[j]+(int)((long long)ex[j][now_sz]*(long long)hs[j][ip]%mod[j]))%mod[j];
      	     now_sz+=2*adj[id][i].size;
         }
         for(j=0;j<2;j++)
         {
             now_hs[j]+=(ex[j][now_sz]<<1)%mod[j];
	          now_hs[j]%=mod[j];
         }
         ip=id;
         ch=id;
     	 now.size=sz[ip]+1;
       	 now.vl[0]=now_hs[0];
       	 now.vl[1]=now_hs[1];
       	 now.id=ip;
   	     while(true)
         {
         	 if(pm[ip]!=ip)
         	 {
         	 	for(j=0;j<2;j++)
         	 	{
	                vl=(now_mb[j][ip]-now_mb[j][pm[ip]]+mod[j])%mod[j];
         	        vl+=(int)((long long)hs[j][ip]*(long long)ex[j][from[ip]]%mod[j]);
         	        vl%=mod[j];
         	        vl=(int)((long long)vl*(long long)inv[j][from[pm[ip]]]%mod[j]);
		    	    vl=(hs[j][pm[ip]]-vl+mod[j])%mod[j];
				    vl=(int)((long long)vl*(long long)ex[j][2]%mod[j]);
				    vl+=(int)((long long)now_hs[j]*(long long)(ex[j][from[ip]-from[pm[ip]]])%mod[j]);
				    vl%=mod[j];
			        vl+=(int)((long long)(now_mb[j][ip]-now_mb[j][pm[ip]])*(long long)inv[j][from[pm[ip]]]%mod[j]);
			   	    vl=(vl%mod[j]+mod[j])%mod[j];
		 		    now_hs[j]=vl;
				    now.size=sz[pm[ip]]+1;
				    now.vl[j]=now_hs[j];
				    now.id=pm[ip];
         	 	}
			    ip=pm[ip];
         	 }
         	 ie=pr[ip];
         	 if(ie<0)
         	 {
         	 	for(j=0;j<2;j++)
 	         	   bw[j][flag][id]=now_hs[j];
 	         	break;
 	         }
             rp.clear();
        	 for(i=0;i<adj[ie].size();i++)
             {
  	 	         	  iq=adj[ie][i].id;
  	 	         	  if(iq==pr[ie])
  	 	         	      continue;
	         	      if(iq==ip)
   	         		      rp.push_back(now);
   	           	      else
   	           	          rp.push_back(adj[ie][i]);
  	 	     }
  	 	     sort(rp.begin(),rp.end());
  	 	     now_hs[0]=now_hs[1]=1;
  	 	     now_sz=1;
	      	 for(i=0;i<rp.size();i++)
	         {
  	 	     	  for(j=0;j<2;j++)
  	 	     	  {
         	 	   	  now_hs[j]+=(int)((long long)ex[j][now_sz]*(long long)rp[i].vl[j]%mod[j]);
         	 	  	  now_hs[j]%=mod[j];
  	 	     	  }
			      now_sz+=2*rp[i].size;
			 }
			 for(j=0;j<2;j++)
			 {
			     now_hs[j]+=(ex[j][now_sz]<<1)%mod[j];
			     now_hs[j]%=mod[j];
			     now.vl[j]=now_hs[j];
			 }
			 now.id=ie;
			 now.size=sz[ie]+1;
 	         ip=ie;
         }

        // if(id==0||id==2)
          //  printf("ie=%d\n",ie);
    }
    for(i=0;i<adj[id].size();i++)
    {
    	ip=adj[id][i].id;
    	if(ip==pr[id])
    	    continue;
	    for(j=i+1;j<adj[id].size();j++)
	    {
    		ix=adj[id][j].id;
    		if(ix!=pr[id])
    		{
		    	if(adj[id][i].size!=adj[id][j].size&&adj[id][i].size!=adj[id][j].size-1)
	    			pm[adj[id][i].id]=pm[id];
	    		break;
		    }
    	}
    	if(j>=adj[id].size())
    	   pm[adj[id][i].id]=pm[id];
		solve(flag,ip,mb);
    }
    to[id]=times++;
    for(j=0;j<2;j++)
    	mb[j]=(mb[j]+(ex[j][to[id]]<<1)%mod[j])%mod[j];
}
int main()
{
	scanf("%d",&n);
	int i,j,s,p,q,id1,id2,root[2],nc,id;
	//printf("orz=%d\n",1+37+37*37*2+37*37*37+37*37*37*37*2+37*37*37*37*37*2);
	for(i=0;i<n;i++)
	    adj[i].clear();
    for(i=0;i<=2*n+2;i++)
       for(j=0;j<2;j++)
       {
      	  if(i==0)
    	     ex[j][i]=1;
 	      else
 	         ex[j][i]=(int)((long long)ex[j][i-1]*(long long)base[j]%mod[j]);
       }
    for(j=0;j<2;j++)
    {
       inv[j][2*n+2]=power(ex[j][2*n+2],mod[j]-2,mod[j]);
       for(i=2*n+1;i>=0;i--)
          inv[j][i]=(int)((long long)inv[j][i+1]*(long long)base[j]%mod[j]);
    }
	for(i=0;i<n-1;i++)
	{
		scanf("%d%d",&id1,&id2);
		id1--;
		id2--;
		pp now;
		now.id=id2;
		adj[id1].push_back(now);
		now.id=id1;
		adj[id2].push_back(now);
	}
	get_size(0,-1);
	nc=0;
	choose_root(0,-1,0,root,nc);
	num=nc;
	for(i=0;i<num;i++)
	   rt[i]=root[i];
    for(i=0;i<num;i++)
    {
    	times=0;
    	//printf("rt[%d]=%d\n",i,rt[i]);
    	get_hash(rt[i],-1);
    	for(j=0;j<n;j++)
    	   pm[j]=j;
    	int mb[2]={0};
    	solve(i,rt[i],mb);
    }
    ha.clear();
    for(i=1;i<num;i++)
    {
    	for(j=0;j<n;j++)
    	{
	    	if(adj[j].size()<4)
  	        {
  	        	for(s=0;s<2;s++)
	    	        bw[s][0][j]=min(bw[s][0][j],bw[s][i][j]);
  	        }
		}
    }
    for(i=0;i<n;i++)
    {
    	if(adj[i].size()<4)
            ha.insert((long long)bw[0][0][i]*(long long)mod[1]+bw[1][0][i]);
    }
	printf("%d\n",ha.size());
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define PB push_back
#define ZERO (1e-10)
#define INF (1<<29)
#define CL(A,I) (memset(A,I,sizeof(A)))
#define DEB printf("DEB!\n");
#define D(X) cout<<"  "<<#X": "<<X<<endl;
#define EQ(A,B) (A+ZERO>B&&A-ZERO<B)
typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef vector<ii> vii;
#define IN(n) int n;scanf("%d",&n);
#define FOR(i, m, n) for (int i(m); i < n; i++)
#define REP(i, n) FOR(i, 0, n)
#define F(n) REP(i, n)
#define FF(n) REP(j, n)
#define FT(m, n) FOR(k, m, n)
#define aa first
#define bb second
void ga(int N,int *A){F(N)scanf("%d",A+i);}
#define M1 (1000000007)
#define M2 (1000000009)
#define B1 (257ll)
#define B2 (13ll)
#define MX (100009)
vi g[MX];
void dw(int u,int p,int d,int *D){
    D[u]=d;
    for(auto i:g[u])if(i^p)dw(i,u,d+1,D);
}
ii ctr(int N,int r=0){
    static int D[MX],U[MX];
    int R,d(0),l(-1);
    dw(r,-1,0,D);
    dw(max_element(D,D+N)-D,-1,0,D);
    F(N)if(D[i]>d)d=D[l=i];
    dw(l,-1,0,U);
    d=D[l]>>1;
    if(!(D[l]&1))F(N)if(D[i]==U[i]&&D[i]==d)return {i,-1};
    ii B;
    F(N)if(D[i]==d&&U[i]==d+1)B.bb=i;
    else if(D[i]==d+1&&U[i]==d)B.aa=i;
    return B;
}
unordered_map<int,ll> dp[MX];
ll gh(int u,int p){
    if(dp[u].count(p))return dp[u][p];
    ll a=10000141,b=1234577,S=0;
    vi Z;
    for(auto&h:g[u])if(h^p)Z.PB(gh(h,u));
    sort(Z.begin(),Z.end());
    for(auto&h:Z)S*=a,S+=h,a*=b;
    return dp[u][p]=S*a+1;
}
int dfs(int u,int p){
    set<ll> T;
    int S=g[u].size()<4u;
    for(auto&h:g[u])if(h^p&&!T.count(gh(h,u)))T.insert(gh(h,u)),S+=dfs(h,u);
    return S;
}
int S,N,a,b;
int main(void){
    scanf("%d",&N);
    if(N==1)return puts("1"),0;
    F(N-1)scanf("%d%d",&a,&b),g[--a].PB(--b),g[b].PB(a);
    ii w=ctr(N);
    S=dfs(w.aa,-1);
    if(~w.bb&&gh(w.aa,-1)==gh(w.bb,-1))S-=dfs(w.bb,w.aa);
    printf("%d\n",S);
    return 0;
}

#include <bits/stdc++.h>
#define LL long long
#define pii pair <LL, LL>
#define xx first
#define yy second
using namespace std;

const int N = 100100;
const LL A1 = 23, B1 = 17, C1 = 233, D1 = 19, mod1 = 1e9 + 7;
const LL A2 = 233, B2 = 19, C2 = 29, D2 = 23, mod2 = 1e9 + 9;

map <pii, pii> mp;
vector <int> g[N];
int u[N], v[N];

pii dfs (int u, int fa) {
    if (mp.find (pii (u, fa)) != mp.end()) return mp[pii (u, fa)];
    vector <pii> tmp;
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if (v == fa) continue;
        tmp.push_back (dfs (v, u));
    }
    sort (tmp.begin(), tmp.end());
    LL h1 = g[u].size(), h2 = g[u].size();
    for (int i = 0; i < tmp.size(); i++) {
        h1 = ((h1 + A1) ^ tmp[i].xx) % mod1;
        h2 = ((h2 + A2) ^ tmp[i].yy) % mod2;
//        h1 = (((h1 * A1 + B1) ^ tmp[i].xx) + C1) % mod1;
//        h2 = (((h2 * A2 + B2) ^ tmp[i].yy) + C2) % mod2;
    }
//    (h1 += B1) %= mod1;
//    (h2 += B2) %= mod2;
    (h1 *= D1) %= mod1;
    (h2 *= D2) %= mod2;
//    cout << u << ' ' << fa << ' ' << h1 << ' ' << h2 << endl;
    return mp[pii (u, fa)] = pii (h1, h2);
}

int main () {
//    freopen ("in", "r", stdin);
    int n;
    cin >> n;
    for (int i = 1; i < n; i++) {
        scanf ("%d%d", &u[i], &v[i]);
        g[u[i]].push_back (v[i]);
        g[v[i]].push_back (u[i]);
    }
    set <pii> st;
    for (int i = 1; i <= n; i++) {
        if (g[i].size() < 4) st.insert (dfs (i, 0));
//        cout << dfs (i, 0).xx << ' ' << dfs (i, 0).yy << endl;
//        if (g[v[i]].size() < 4) st.insert (dfs (v[i], u[i]));
    }
    cout << st.size() << endl;
}

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 210000;

int n;
int oke[maxn],okp[maxn];
struct edge{int y,nex;}a[maxn<<1]; int len,fir[maxn];
inline void ins(const int x,const int y){a[++len]=(edge){y,fir[x]};fir[x]=len;}

int siz[maxn],mxs[maxn];
void dfs(const int x,const int fa)
{
	siz[x]=1;
	for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa)
	{
		dfs(y,x);
		siz[x]+=siz[y];
		mxs[x]=max(mxs[x],siz[y]);
	}
}
int root,t1,t2;
int d[maxn],f[maxn],f2[maxn];
bool cmp(const int x,const int y){return f[x]==f[y]?f2[x]<f2[y]:f[x]<f[y];}
int t[maxn],tp;
void Hash(const int x,const int fa)
{
	siz[x]=1;
	for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa&&oke[k]) Hash(y,x),siz[x]+=siz[y];
	tp=0; for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa&&oke[k]) t[++tp]=y;
	sort(t+1,t+tp+1,cmp);
	d[x]=tp+(fa!=0);
	f[x]=f2[x]=siz[x];
	for(int i=1;i<=tp;i++)
	{
		int y=t[i];
		f[x]=f[x]*(siz[y]+1)*f[y];
		f2[x]=f2[x]+(siz[y]+2)*(f2[y]+1);
	}
}
int ans[maxn];
void cal(const int x,const int fa)
{
	if(okp[x]&&d[x]<4) ans[x]++;
	for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa&&oke[k]) cal(y,x);
	tp=0; for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa&&oke[k]) t[++tp]=y;
	sort(t+1,t+tp+1,cmp);
	for(int i=1;i<=tp;i++)
	{
		int y=t[i],ty=t[i-1];
		if(f[y]!=f[ty]||f2[y]!=f2[ty]) ans[x]+=ans[y];
	}
}

int main()
{
	//freopen("tmp.in","r",stdin);
	//freopen("tmp.out","w",stdout);

	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int x,y; scanf("%d%d",&x,&y);
		ins(x,y),ins(y,x);
	}
	dfs(1,0);
	for(int i=1;i<=n;i++) if(mxs[i]*2<=n&&(n-siz[i])*2<=n)
	{
		if(!t1) t1=i;
		else t2=i;
	}
	for(int i=1;i<=len;i++) oke[i]=1;
	for(int i=1;i<=n;i++) okp[i]=1;
	if(t2)
	{
		for(int k=fir[t1],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y==t2) oke[k]=0;
		for(int k=fir[t2],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y==t1) oke[k]=0;
		okp[root=++n]=0; ins(root,t1),ins(root,t2);
		oke[len-1]=oke[len]=1;
	}
	else root=t1;

	Hash(root,0);
	cal(root,0);
	printf("%d\n",ans[root]);

	return 0;
}

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>

const int N = 100000;

int head[N], to[N << 1], next[N << 1], tree_hash[N << 1];
std::map<std::vector<int>, int> hashes;

int get_hash(const std::vector<int>& hash)
{
    if (!hashes.count(hash)) {
        auto count = hashes.size();
        hashes[hash] = count;
    }
    return hashes[hash];
}

int get_tree_hash(int edge)
{
    int& ref = tree_hash[edge];
    if (ref == -1) {
        std::vector<int> hashes;
        for (int iterator = head[to[edge]]; ~iterator; iterator = next[iterator]) {
            if (to[iterator] != to[edge ^ 1]) {
                hashes.push_back(get_tree_hash(iterator));
            }
        }
        std::sort(hashes.begin(), hashes.end());
        ref = get_hash(hashes);
    }
    return ref;
}

int main()
{
#ifdef LOCAL_JUDGE
    freopen("D.in", "r", stdin);
#endif
    int n;
    while (scanf("%d", &n) == 1) {
        for (int i = 0; i < n - 1 << 1; ++ i) {
            scanf("%d", to + i);
            to[i] --;
        }
        memset(head, -1, sizeof(*head) * n);
        for (int i = 0; i < n - 1 << 1; ++ i) {
            auto& h = head[to[i ^ 1]];
            next[i] = h;
            h = i;
        }
        memset(tree_hash, -1, sizeof(*tree_hash) * (n << 1));
        std::vector<std::vector<int>> hashes;
        for (int u = 0; u < n; ++ u) {
            std::vector<int> hash;
            for (int iterator = head[u]; ~iterator; iterator = next[iterator]) {
                hash.push_back(get_tree_hash(iterator));
            }
            if (static_cast<int>(hash.size()) < 4) {
                std::sort(hash.begin(), hash.end());
                hashes.push_back(hash);
            }
        }
        std::sort(hashes.begin(), hashes.end());
        hashes.erase(std::unique(hashes.begin(), hashes.end()), hashes.end());
        printf("%d\n", static_cast<int>(hashes.size()));
    }
}

#include <bits/stdc++.h>
using namespace std;
#define N 123456
struct Hash {
	size_t operator()(const vector<int> &a) const {
		size_t ret = 0;
		for(auto &&x:a) ret ^= hash<int>()(x);
		return ret;
	}
};
set<int> cat;
vector<int> h[N];
unordered_map<vector<int>, int, Hash> val;
unordered_map<int, int> f[N];
int deg[N], tot;
int label(int x, int fa){
	if(f[x][fa]) return f[x][fa];
	vector<int> tag;
	for(auto v:h[x]) if(v != fa)
		tag.push_back(label(v, x));
	sort(tag.begin(), tag.end());
	if(!val[tag]) val[tag] = ++tot;
	return f[x][fa] = val[tag];
}
int main(){
	int n,x,y;
	scanf("%d",&n);
	for(int i = 1; i < n; i++) {
		scanf("%d%d", &x, &y);
		h[x].push_back(y); deg[x]++;
		h[y].push_back(x); deg[y]++;
	}
	for(int i = 1; i <= n; i++) if(deg[i] < 4)
		cat.insert(label(i, 0));
	printf("%d\n", cat.size());
}

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

#define RG register
#define ll long long
#define For(i, f, t) for (RG int i = f; i <= t; ++i)
#define par(x, a) For (i, 1, x) printf("%d ", a[i]); puts("");

const int N = 111111;

int n, cnt;
int ans[N];
vector<int> e[N];
map<int, int> mp[N];
map<vector<int>, int> H;
set<int> st;

int dp(int x, int fa)
{
//	printf("%d %d\n", x, fa);
	if (mp[x][fa]) return mp[x][fa];
	vector<int> tmp;
	for (int i = 0, _ = e[x].size(); i < _; i++)
		if (e[x][i] != fa) tmp.push_back(dp(e[x][i], x));
	sort(tmp.begin(), tmp.end());
	if (!H[tmp]) H[tmp] = ++cnt;
	return mp[x][fa] = H[tmp];
}

int main()
{
	scanf("%d", &n);
	For (i, 2, n)
	{
		int u, v; scanf("%d %d", &u, &v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	For (i, 1, n)
		if (e[i].size() < 4)
			st.insert(dp(i, 0));
	printf("%d\n", st.size());
	return 0;
}

#include <bits/stdc++.h>

#define f(i,a,b) for( ll i = a; i < (ll) b ; i++ )
#define af(i,a,b) for( ll i = a; i >= (ll) b ; i--)
#define rep(i,a,b,k) for(ll i = a; i < (ll) b ; i+= k )
#define arep(i,a,b,k) for( ll i = a; i >= (ll) b ; i-= k)
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
#define sz(a) (ll) a.size()
#define all(a) a.begin(), a.end()
#define sor(a) sort( a.begin(), a.end() )
#define fastio ios_base::sync_with_stdio(false);cin.tie(NULL)
#define inter ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nuintptr)
using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> ii ;
typedef vector<ll>  vi ;
typedef vector<ii> vii ;

const ll MAX= 2e5+10;
const ll inf =1e9;

map<vi,ll> m;
vi adj[MAX];
ll x[MAX],y[MAX],cont=1;
set<ll> num;
ll pos(vi a){
	if(m[a]!=0) return m[a];
	m[a]=cont++;
	return m[a];
}

void dfs(ll u,ll f){
	vi aux;
	f(i,0,adj[u].size()){
		ll v = adj[u][i];
		if(v==f) continue;
		dfs(v,u);
		aux.push_back(x[v]);
	}
	while(aux.size()<4)
		aux.push_back(-1);
	sort(all(aux));
	x[u]= pos(aux);

}

void dfs1(ll u,ll f){
	f(i,0,adj[u].size()){
		ll v = adj[u][i];
		if(v==f) continue;
		vi aux;
		f(j,0,adj[u].size()){
			ll w = adj[u][j];
			if(w==v || w==f) continue;
			aux.push_back(x[w]);
		}
		if(f!=0) aux.push_back(y[u]);
		while(aux.size()<4) aux.push_back(-1);
		sort(all(aux));
		y[v] = pos(aux);
		if(adj[v].size()<4){
			vi aux1;
			aux1.push_back(y[v]);
			f(j,0,adj[v].size()){
				ll w = adj[v][j];
				if(w==u) continue;
				aux1.push_back(x[w]);
			}
			aux1.push_back(1);
			while(aux1.size()<4) aux1.push_back(-1);
			sort(all(aux1));
			num.insert(pos(aux1));
		}
		dfs1(v,u);
	}

}

int main(){
	fastio;
	ll tc,n,a,b,q,m;
	tc=1;
	cin>>n;
	f(i,1,n){
		cin>>a>>b;
		adj[a].push_back(b);
		adj[b].push_back(a);
	}
	dfs(1,0);
	dfs1(1,0);
	if(adj[1].size()<4){
		vi aux;
		aux.push_back(1);
		f(i,0,adj[1].size()) aux.push_back(x[adj[1][i]]);
		while(aux.size()<4) aux.push_back(-1);
		sort(all(aux));
		num.insert(pos(aux));
	}
	cout<<num.size()<<endl;
}

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <ctime>
#include <map>
#include <queue>
#include <cstdlib>
#include <string>
#include <climits>
#include <set>
#include <vector>
using namespace std;
inline int read(){
	int k=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();}
	return k*f;
}
set<int>s;
map<int,int>f[100010];
map<vector<int>,int>mp;
int nedge=0,p[200010],nex[200010],head[200010];
int d[200010],cnt=0;
inline void addedge(int a,int b){
	p[++nedge]=b;nex[nedge]=head[a];head[a]=nedge;
}
inline int dfs(int x,int fa){
	if(f[x][fa])return f[x][fa];
	vector<int>q;
	for(int k=head[x];k;k=nex[k])
		if(p[k]!=fa)q.push_back(dfs(p[k],x));
	sort(q.begin(),q.end());
	if(!mp[q])mp[q]=++cnt;
	return f[x][fa]=mp[q];
}
int main()
{
	int n=read();
	for(int i=1;i<n;i++){
		int x=read(),y=read();
		addedge(x,y);addedge(y,x);
		d[x]++;d[y]++;
	}
	for(int i=1;i<=n;i++)if(d[i]<4)s.insert(dfs(i,0));
	printf("%d",s.size());
	return 0;
}

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int n,cnt,dag[N];
vector<int> g[N];	set<int> res;
map<int,int> mp[N];	map<vector<int>,int> Hash;
int dfs(int x,int fa){
	if(mp[x][fa])	return mp[x][fa];
	vector<int> t;
	for(auto to:g[x]){
		if(to!=fa)	t.push_back(dfs(to,x));
	}
	sort(t.begin(),t.end());
	if(!Hash[t])	Hash[t]=++cnt;
	return mp[x][fa]=Hash[t];
}
signed main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int x,y;	cin>>x>>y;	dag[x]++;	dag[y]++;
		g[x].push_back(y),g[y].push_back(x);
	}
	for(int i=1;i<=n;i++)	if(dag[i]<4){
		res.insert(dfs(i,0));
	}
	cout<<res.size();
	return 0;
}

#include <bits/stdc++.h>
#define mset(a, b) memset(a, b, sizeof(a))
#define mcpy(a, b) memcpy(a, b, sizeof(a))
#define rg register
using namespace std;
typedef long long LL;
const int MAXN = 100005;

template <typename T> inline void read(T &AKNOI) {
	T x = 0, flag = 1;
	char ch = getchar();
	while (!isdigit(ch)) {
		if (ch == '-') flag = -1;
		ch = getchar();
	}
	while (isdigit(ch)) {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	AKNOI = flag * x;
}

int n, deg[MAXN], id;
vector<int> g[MAXN];
map<int, int> dp[MAXN];
map<vector<int>, int> hsh;
set<int> ans;

int DFS(int u, int fa) {
    if (dp[u][fa]) return dp[u][fa];
    vector<int> son;
    for (auto v : g[u]) {
        if (v == fa) continue;
        son.push_back(DFS(v, u));
    }
    sort(son.begin(), son.end());
    if (hsh[son] == 0) hsh[son] = ++id;
    return dp[u][fa] = hsh[son];
}

void init() {
    read(n);
    for (int i = 1, u, v; i < n; ++i) {
        read(u); read(v);
        g[u].push_back(v);
        g[v].push_back(u);
        ++deg[u]; ++deg[v];
    }
}

void solve() {
    for (int i = 1; i <= n; ++i) {
        if (deg[i] < 4) {
            ans.insert(DFS(i, 0));
        }
    }
    printf("%d\n", ans.size());
}

int main() {
	init();
	solve();
	return 0;
}

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
struct Edge{
	int v,nxt;
}e[200010];int tot;
int deg[100010];
int first[100010];
void build(int u,int v)
{
	e[++tot]=(Edge){v,first[u]};
	first[u]=tot;deg[u]++;
	return ;
}
int siz[100010];
int mxsiz[100010];
int f[100010];
const int Mod=1000000007;
const int M=10007;
int h[100010];
void dfs(int u,int lst)
{
	siz[u]=1;mxsiz[u]=0;
	for(int i=first[u];i;i=e[i].nxt)
		if(e[i].v!=lst){
			dfs(e[i].v,u);siz[u]+=siz[e[i].v];
			mxsiz[u]=max(mxsiz[u],siz[e[i].v]);
		}
	return ;
}
void solve(int u,int lst)
{
	h[u]=1;f[u]=(deg[u]<4);
	vector<pair<int,int> >val;
	for(int i=first[u];i;i=e[i].nxt)
		if(e[i].v!=lst){
			solve(e[i].v,u);
			val.push_back(make_pair(h[e[i].v],f[e[i].v]));
		}
	sort(val.begin(),val.end());
	int pre=Mod+1;
	for(int i=0;i<val.size();i++)
	{
		int H=val[i].first,F=val[i].second;
		h[u]=((1ll*h[u]*M%Mod*H%Mod)^H)%Mod;
		if(H!=pre){
			pre=H;
			f[u]+=F;
		}
	}
	return ;
}
int main()
{
	int n;scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d %d",&u,&v);
		build(u,v);
		build(v,u);
	}
	dfs(1,0);
	int S=0,T=0;
	for(int i=1;i<=n;i++)
		if(max(mxsiz[i],n-siz[i])<=n/2)
		{
			T=S;
			S=i;
		}
	if(T){
		solve(S,T);
		solve(T,S);
		if(h[S]!=h[T])printf("%d\n",f[S]+f[T]);
		else printf("%d\n",f[S]);
	}
	else{
		solve(S,0);
		printf("%d\n",f[S]);
	}
	return 0;
}

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<ctime>
#include<cstdlib>
#include<string>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#include<bitset>
#include<vector>
#define rep(x,a,b) for (int x=a;x<=(int)b;x++)
#define drp(x,a,b) for (int x=a;x>=(int)b;x--)
#define cross(x,a) for (int x=hd[a];~x;x=nx[x])
#define ll long long
#define inf (1<<29)
#define PII pair<int,int>
#define PDD pair<double,double>
#define mk(a,b) make_pair(a,b)
#define fs first
#define sc second
#define pb push_back
using namespace std;
inline ll rd(){
	ll x=0;int ch=getchar(),f=1;
	while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
	if (ch=='-'){f=-1;ch=getchar();}
	while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
inline void rt(ll x){
	if (x<0) putchar('-'),x=-x;
	if (x>=10) rt(x/10),putchar(x%10+'0');
		else putchar(x+'0');
}
const int maxn=100005;
int to[maxn<<1],nx[maxn<<1],hd[maxn],cnt;
void addedge(int u,int v){
	to[cnt]=v;nx[cnt]=hd[u];hd[u]=cnt++;
}
int a[maxn],b[maxn],c[maxn],cal,d[maxn],vis[maxn<<3];
#define mod 10000007
int HD[mod],NX[maxn<<3],CNT;
PII TO[maxn<<3];
#define CROSS(i,u) for (int i=HD[u];~i;i=NX[i])
int find(int x,int y){
	CROSS(i,x){
		PII v=TO[i];
		if (v.fs==y) return v.sc;
	}
	return 0;
}
void add(int x,int y,int v){
	TO[CNT]=mk(y,v),NX[CNT]=HD[x],HD[x]=CNT++;
}
void dfs1(int u,int fa){
	cross(i,u){
		int v=to[i];
		if (v!=fa) dfs1(v,u);
	}
	int tmp[4]={0},tc=0;
	cross(i,u){
		int v=to[i];
		if (v!=fa) tmp[tc++]=a[v];
	}
	sort(tmp,tmp+4);
	int hs1=0,hs2=0;
	rep(i,0,3) hs1=((ll)hs1*233+tmp[i])%mod,hs2=((ll)hs2*2333+tmp[i])%mod;
	a[u]=find(hs1,hs2);
	if (!a[u]) a[u]=++cal,add(hs1,hs2,a[u]);
}
void dfs2(int u,int fa){
	int tmp[4]={0},tc=0;
	cross(i,u){
		int v=to[i];
		if (v==fa) tmp[tc++]=c[v];else tmp[tc++]=a[v];
	}
	sort(tmp,tmp+4);
	int hs1=0,hs2=0;
	rep(i,0,3) hs1=((ll)hs1*233+tmp[i])%mod,hs2=((ll)hs2*2333+tmp[i])%mod;
	b[u]=find(hs1,hs2);
	if (!b[u]) b[u]=++cal,add(hs1,hs2,b[u]);
	cross(i,u){
		int v=to[i];
		if (v==fa) continue;
		rep(j,0,3) if (tmp[j]==a[v]){tmp[j]=0;break;}
		sort(tmp,tmp+4);
		hs1=hs2=0;
		rep(j,0,3) hs1=((ll)hs1*233+tmp[j])%mod,hs2=((ll)hs2*2333+tmp[j])%mod;
		c[u]=find(hs1,hs2);
		if (!c[u]) c[u]=++cal,add(hs1,hs2,c[u]);
		dfs2(v,u);
		tmp[0]=a[v];
	}
}
int n;
int main(){
	n=rd();
	memset(hd,-1,sizeof hd);
	memset(HD,-1,sizeof HD);
	rep(i,1,n-1){
		int u=rd(),v=rd();
		addedge(u,v),addedge(v,u);
		d[u]++,d[v]++;
	}
	dfs1(1,0);
	dfs2(1,0);
	int ans=0;
	rep(i,1,n) if (d[i]!=4&&!vis[b[i]]) vis[b[i]]=1,ans++;
	rt(ans),putchar('\n');
}

#include <iostream>
#include <map>
#include <set>
#include <vector>

using namespace std;

int n, cnt = 0;
vector <int> a;
set <int> b;
vector <bool> used;
vector <vector <int> > g;
vector <multiset <int> > value;
map <multiset <int>, int> num;

void dfs(int x = 1)
{
    used[x] = true;
    multiset <int> key;
    for (int i = 0; i < (int)g[x].size(); i++)
    {
        int to = g[x][i];
        if (!used[to])
        {
            dfs(to);
            key.insert(a[to]);
        }
    }
    for (int i = 0 ; i < 4 - (int)g[x].size(); i++)
        key.insert(-1);
    if (x != 1)
        key.insert(-1);

    if (num.count(key))
        a[x] = num[key];
    else
    {
        value.push_back(key);
        a[x] = num[key] = cnt++;
    }
}

void dfstwo(int x = 1, int prev = -1)
{
    multiset <int> key = value[a[x]];
    if (x != 1)
    {
        key.erase(key.find(-1));
        key.insert(prev);
    }

    if ((int)g[x].size() < 4)
    {
        if (x == 1)
            b.insert(a[x]);
        else
        {
            if (num.count(key))
                b.insert(num[key]);
            else
            {
                num[key] = cnt++;
                b.insert(num[key]);
            }
        }
    }

    used[x] = true;
    for (int i = 0; i < (int)g[x].size(); i++)
    {
        int to = g[x][i];
        if (!used[to])
        {
            key.erase(key.find(a[to]));
            key.insert(-1);

            if (!num.count(key))
                num[key] = cnt++;

            dfstwo(to, num[key]);

            key.erase(key.find(-1));
            key.insert(a[to]);
        }
    }
}

int main()
{
    ios_base::sync_with_stdio(false), cin.tie(nullptr);

    cin >> n;
    g.resize(n + 1);
    a.resize(n + 1);
    used.resize(n + 1, false);
    for (int i = 0; i < n - 1; i++)
    {
        int from, to;
        cin >> from >> to;
        g[from].push_back(to);
        g[to].push_back(from);
    }

    dfs();

    used.clear();
    used.resize(n + 1, false);
    dfstwo();

    cout << b.size();
    return 0;
}

#include<cstdlib>
#include<cstdio>
#include<map>
#include<set>
#include<algorithm>
#include<vector>
using namespace std;
const int N=100010;
map<vector<int>,int>mp;
set<int>s;
int n,cnt,mpnum,deg[N];
map<int,int>D[N];
struct node{int v;node *next;}pool[N<<1],*h[N];
void add(int u,int v)
{
	node *p=&pool[++cnt],*q=&pool[++cnt];
	p->v=v;p->next=h[u];h[u]=p;
	q->v=u;q->next=h[v];h[v]=q;
}
int dfs(int u,int fa)
{
	if(D[u][fa]) return D[u][fa];
	vector<int>tmp;
	for(node *t=h[u];t;t=t->next)
		if(t->v^fa)
			tmp.push_back(dfs(t->v,u));
	sort(tmp.begin(),tmp.end());
	if(!mp[tmp]) mp[tmp]=++mpnum;
	return D[u][fa]=mp[tmp];
}

int main()
{
	scanf("%d",&n);
	for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),deg[x]++,deg[y]++;
	for(int i=1;i<=n;i++)
		if(deg[i]<4) s.insert(dfs(i,0));
	printf("%d\n",s.size());
}

#include <iostream>
#include <cstdio>
#include <map>

#define ll long long
#define Max 100005

using namespace std;

inline char gc(){
	static char buf[100000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){
	ll x=0;char ch=gc();bool positive=1;
	for(;!isdigit(ch);ch=gc())if(ch=='-')positive=0;
	for(;isdigit(ch);ch=gc())x=x*10+ch-'0';
	return positive?x:-x;
}

inline void write(ll x){
	if(x<0)x=-x,putchar('-');
	if(x>9)write(x/10);putchar(x%10+'0');
}

inline void writeln(ll x){
	write(x);puts("");
}

const ll mod1=998244353,mod2=1000000007;

struct Hash{
	ll num1,num2;
	inline bool operator<(const Hash&x)const{
		if(num1!=x.num1)return num1<x.num1;
		return num2<x.num2;
	}
	inline Hash operator*(const Hash&x)const{
		Hash ans;
		ans.num1=num1*x.num1%mod1;
		ans.num2=num2*x.num2%mod2;
		return ans;
	}
	inline Hash operator+(const Hash&x)const{
		Hash ans;
		ans.num1=(num1+x.num1)%mod1;
		ans.num2=(num2+x.num2)%mod2;
		return ans;
	}
};

struct Edge{
	ll v,to;
}e[Max*2];

ll n,l,r,ans,size,deg[Max],head[Max];
map<ll,bool>f[Max];
map<ll,Hash>g[Max];
map<Hash,bool>vis;

inline void add(ll u,ll v){
	e[++size].v=v;e[size].to=head[u];head[u]=size;
}

inline Hash calc(ll u,ll fa){
	if(f[u][fa])return g[u][fa];
	Hash sum=(Hash){1,1};
	for(ll i=head[u];i;i=e[i].to){
		ll v=e[i].v;
		if(v==fa)continue;
		Hash now=calc(v,u);
		sum=sum+now*now*now;
	}
	f[u][fa]=true;
	g[u][fa]=sum;
	return sum;
}

int main(){
	n=read();
	for(ll i=1;i<n;i++){
		l=read();r=read();
		add(l,r);
		add(r,l);
		deg[l]++;
		deg[r]++;
	}
	for(ll i=1;i<=n;i++){
		if(deg[i]<4){
			Hash k=calc(i,i);
			// cout<<k<<endl;
			if(!vis[k]){
				ans++;
				vis[k]=true;
			}
		}
	}
	writeln(ans);
	return 0;
}

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
using namespace std;
const int N = 1e5, K = 4;
vector<int> g[N];
set<int> s;
int a[N];
int get_index(const vector<int> x)
{
	static map<vector<int>, int> m;
	static int cnt;
	if (m.find(x) == m.end()) m[x] = cnt++;
	return m[x];
}
void dfs_pre(int u, int fa)
{
	vector<int> x;
	for (int v : g[u])
		if (v != fa)
		{
			dfs_pre(v, u);
			x.push_back(a[v]);
		}
	sort(x.begin(), x.end());
	a[u] = get_index(x);
}
void dfs(int u, int fa)
{
	vector<int> x;
	if (g[u].size() < K)
	{
		for (int v : g[u]) x.push_back(a[v]);
		sort(x.begin(), x.end());
		s.insert(get_index(x));
	}
	sort(g[u].begin(), g[u].end(), [](int x, int y) { return a[x] < a[y]; });
	x.clear();
	for (int i = 1; i < g[u].size(); i++) x.push_back(a[g[u][i]]);
	int t = a[u];
	for (int i = 0; i < g[u].size(); i++)
	{
		if (g[u][i] != fa)
		{
			a[u] = get_index(x);
			dfs(g[u][i], u);
		}
		if (i < g[u].size() - 1) x[i] = a[g[u][i]];
	}
	a[u] = t;
}
int main()
{
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	for (int i = 0; i < n - 1; i++)
	{
		int x, y;
		cin >> x >> y;
		x--, y--;
		g[x].push_back(y);
		g[y].push_back(x);
	}
	dfs_pre(0, -1);
	dfs(0, -1);
	cout << s.size() << endl;
}

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
#include<string>
#define LL long long
using namespace std;
const int MAXN = 100005;
const LL MOD[4] = {199999LL, 30319LL, 123401LL, 1000000007LL};
int n;
int root;
int ans;
vector<int> e[MAXN];
int visited[MAXN];
int size[MAXN];
int weight[MAXN];
LL h[MAXN][4];
LL hash[MAXN][4];
int id[2];
inline void init(){//��ʼ����ϣ��
	for(int i = 1; i <= n + 2; i++){
		h[i][0] = (LL)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD[0];
		h[i][1] = (LL)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD[1];
		h[i][2] = (LL)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD[2];
		h[i][3] = (LL)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD[3];
	}
}
void dfs(int x){//��һ��dfs���ҳ����ģ�sizeΪ��dfs��������С��weightΪ�����������ָ����󲿷ֵĴ�С��
	visited[x] = true;
	size[x] = 1;
	weight[x] = 0;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		if(!visited[y]){
			dfs(y);
			size[x] += size[y];
			weight[x] = max(size[y], weight[x]);
		}
	}
	if(n - size[x] > weight[x]) weight[x] = n - size[x];
}
void add_edge(int x, int y){
	e[x].push_back(y);
	e[y].push_back(x);
}
void dfs2(int x, int ht){//�ڶ���dfs��������Ϊ���������������hashֵ��htΪ�ڵ����
	visited[x] = true;
	hash[x][0] = hash[x][1] = hash[x][2] = hash[x][3] = 1LL;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		if(!visited[y]){
			dfs2(y, ht + 1);
			hash[x][0] += hash[y][0];
			hash[x][1] += hash[y][1];
			hash[x][2] += hash[y][2];
			hash[x][3] += hash[y][3];
		}
	}
	hash[x][0] = (hash[x][0] * h[ht][0]) % MOD[0];
	hash[x][1] = (hash[x][1] * h[ht][1]) % MOD[1];
	hash[x][2] = (hash[x][2] * h[ht][2]) % MOD[2];
	hash[x][3] = (hash[x][3] * h[ht][3]) % MOD[3];
	hash[x][1] = (hash[x][1] * hash[x][1]) % MOD[1];
}
void dfs3(int x, int ht){//������dfs������answer��htΪ�ڵ���ȣ�ͬ��������ֻ��������һ����
	LL s[6][4], cnt = 0, ok;
	visited[x] = true;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		ok = 1;
		if(visited[y])continue;
		for(int j = 0; j < cnt; j++)
		if(hash[y][0] == s[j][0] && hash[y][1] == s[j][1] && hash[y][2] == s[j][2] && hash[y][3] == s[j][3]){//����
			ok = 0;
			break;
		}
		if(!ok)continue;
		s[cnt][0] = hash[y][0];
		s[cnt][1] = hash[y][1];
		s[cnt][2] = hash[y][2];
		s[cnt][3] = hash[y][3];
		cnt++;
		dfs3(y, ht + 1);
	}
	if(e[x].size() < 4) ans++;//����ɼӣ�+1s
}
int main(){
	srand((int)time(0));
	scanf("%d", &n);
	init();
	for(int i = 1; i < n; i++){//��ͼ
		int x, y;
		scanf("%d%d", &x, &y);
		add_edge(x, y);
	}
	dfs(1);
	for(int i = 1; i <= n; i++){//�ҳ�����
		if(weight[i] <= n / 2){
			id[1] = id[0];
			id[0] = i;
		}
	}
	if(id[1]){//����������ġ�������ô�������м��һ������Ϊ��������answer��ȻҪ������������1s
		ans = -1;
		add_edge(n + 1, id[0]);
		add_edge(n + 1, id[1]);
		vector<int> ::iterator Iter;
		Iter = find(e[id[0]].begin(), e[id[0]].end(), id[1]);
		if(Iter == e[id[0]].end()){
			printf("-1\n");
			return 0;
		}
		e[id[0]].erase(Iter);
		Iter = find(e[id[1]].begin(), e[id[1]].end(), id[0]);
		if(Iter == e[id[1]].end()){
			printf("-1\n");
			return 0;
		}
		e[id[1]].erase(Iter);
		root = ++n;
	}
	else root = id[0];
	memset(visited, 0, sizeof(visited));
	dfs2(root, 1);
	memset(visited, 0, sizeof(visited));
	dfs3(root, 1);
	printf("%d\n", ans);
	return 0;
}

#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//using namespace __gnu_pbds;
using namespace std;

// (づ°ω°)づﾐe★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜

#define Foreach(i, c) for(__typeof((c).begin()) i = (c).begin(); i != (c).end(); ++i)
#define For(i,a,b) for(int (i)=(a);(i) < (b); ++(i))
#define rof(i,a,b) for(int (i)=(a);(i) > (b); --(i))
#define rep(i, c) for(auto &(i) : (c))
#define x first
#define y second
#define pb push_back
#define mp make_pair
#define PB pop_back()
#define iOS ios_base::sync_with_stdio(false)
#define sqr(a) (((a) * (a)))
#define all(a) a.begin() , a.end()
#define error(x) cerr << #x << " = " << (x) <<endl
#define Error(a,b) cerr<<"( "<<#a<<" , "<<#b<<" ) = ( "<<(a)<<" , "<<(b)<<" )\n";
#define Error3(a,b,c) cerr<<"("<<#a<<" , "<<#b<<" , "<<#c<<" ) = ( "<<(a)<<" , "<<(b)<<" , "<<(c)<<")\n";
#define Error4(a,b,c,d) cerr<<"("<<#a<<" , "<<#b<<" , "<<#c<<" , "<<#d<<" ) = ( "<<(a)<<" , "<<(b)<<" , "<<(c)<<" , "<<(d)<<")\n";
#define Error5(a,b,c,d,e) cerr<<"("<<#a<<" , "<<#b<<" , "<<#c<<" , "<<#d<<" , "<<#e<<" ) = ( "<<(a)<<" , "<<(b)<<" , "<<(c)<<" , "<<(d)<<" , "<<(e)<<")\n";
#define errop(a) cerr<<#a<<" = ( "<<((a).x)<<" , "<<((a).y)<<" )\n";
#define coud(a,b) cout<<fixed << setprecision((b)) << (a)
#define L(x) (((x)<<1)+1)
#define R(x) (((x)<<1)+2)
#define umap unordered_map
//#define double long double
#define mod 1000000007
#define mod1 1000000009
#define LIMIT 10000000000000000LL
#define INF 10000000000LL
#define MAX1 1000000000
const int inf=0x3f3f3f3f;
const long double pi=acos(-1.0);
#define MAX 50010
#define N 100010
const string debug_line="yolo";
#define debug error(debug_line)
#define read() freopen("mergedoutput.txt","r",stdin)
#define write() freopen("output.txt","w",stdout)
//template <typename T> using os =  tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
typedef long long ll;
typedef pair<int,int>pii;
typedef vector<int> vi;
typedef complex <long double> complex_t;
const long double PI = acos((long double)-1.0);
const long double eps=1e-6;

vi Adj[100010];
bool visited[100010];
int counter1=0;
int b[100010];
int a[100010];
map<vi,int> mp1;

void DFS(int u,int p){
	visited[u]=true;
	vi res;
	rep(t1,Adj[u]){
		if(t1!=p){
			DFS(t1,u);
			res.pb(a[t1]);
		}
	}
	while(res.size()!=4){
		res.pb(-1);
	}
	sort(all(res));
	if(mp1.count(res)==0){
		mp1[res]=counter1++;
	}
	// Error(u,mp1[res]);
	a[u]=mp1[res];
}

void revDFS(int u,int p,int prev1){
	// error(u);
	visited[u]=true;
	vi res;
	rep(t1,Adj[u]){
		if(t1!=p){
			res.pb(a[t1]);
		}
	}
	if(u!=1){
		res.pb(prev1);
	}
	while(res.size()<4){
		res.pb(-1);
	}
	// error(u);
	// rep(t1,res){
	// 	printf("%d ",t1);
	// }
	// printf("\n");
	sort(all(res));
	if(mp1.count(res)==0){
		mp1[res]=counter1++;
	}
	b[u]=mp1[res];
	rep(t1,Adj[u]){
		if(t1!=p){
			vi res1;
			rep(t2,Adj[u]){
				if(t2!=t1 && t2!=p){
					res1.pb(a[t2]);
				}
				else if(t2!=t1 && t2==p){
					res1.pb(prev1);
				}
			}
			while(res1.size()<4){
				res1.pb(-1);
			}
			sort(all(res1));
			if(mp1.count(res1)==0){
				mp1[res1]=counter1++;
			}
			revDFS(t1,u,mp1[res1]);
		}
	}
}

int main(){
	int n;
	scanf("%d",&n);

	For(i,1,n){
		int u1,v1;
		scanf("%d%d",&u1,&v1);
		Adj[u1].pb(v1);
		Adj[v1].pb(u1);
	}

	DFS(1,0);
	memset(visited,0,sizeof(visited));
	// error(counter1);
	debug;
	revDFS(1,0,-1);
	debug;
	int answer1=0;
	set<int> s1;
	For(i,1,n+1){
		if(Adj[i].size()<=3){
			s1.insert(b[i]);
		}
	}
	printf("%d\n",(int)s1.size());
return 0;}

#include<bits/stdc++.h>
const int maxN = 2e5 + 10;
std::map<std::vector<int>, int> map;
std::map<int, std::map<int, int> > fa;
std::set<int> set;

int head[maxN], next[maxN], to[maxN], deg[maxN], totE, n, cur;
void AddEdge(int u,int v) {
  next[++totE] = head[u]; head[u] = totE; to[totE] = v; deg[u]++;
  next[++totE] = head[v]; head[v] = totE; to[totE] = u; deg[v]++;
}

int dfs(int o,int p) {
  if(fa[o][p] != 0) return fa[o][p];

  std::vector<int> tmp;

  for(int i = head[o]; i; i = next[i]) {
    int v = to[i];
    if(v != p)
      tmp.push_back(dfs(v, o));
  }

  std::sort(tmp.begin(), tmp.end());

  if(!map.count(tmp)) map[tmp] = ++cur;

  return fa[o][p] = map[tmp];
}

int main() {
  if(fopen("input.txt","r")) {
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
  }

  scanf("%d", &n);
  for(int i = 2, u, v;i <= n; ++i) {
    scanf("%d%d", &u, &v); AddEdge(u, v);
  }

  for(int i = 1;i <= n; ++i)
    if(deg[i] < 4)
      set.insert(dfs(i, 0));

  printf("%d", (int) set.size());

  return 0;
}

#include <map>
#include <set>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

inline char read(){
    static const int IN_LEN=1000000;
    static char buf[IN_LEN],*s,*t;
    return (s==t?t=(s=buf)+fread(buf,1,IN_LEN,stdin),(s==t?-1:*s++):*s++);
}
template<class T>
inline void read(T &x){
    static bool iosig;
    static char c;
    for (iosig=false,c=read();!isdigit(c);c=read()){
        if (c=='-') iosig=true;
        if (c==-1) return;
    }
    for (x=0;isdigit(c);c=read()) x=((x+(x<<2))<<1)+(c^'0');
    if (iosig) x=-x;
}
const int OUT_LEN=10000000;
char obuf[OUT_LEN],*ooh=obuf;
inline void print(char c){
    if (ooh==obuf+OUT_LEN) fwrite(obuf,1,OUT_LEN,stdout),ooh=obuf;
    *ooh++=c;
}
template<class T>
inline void print(T x){
    static int buf[30],cnt;
    if (x==0) print('0');
    else{
        if (x<0) print('-'),x=-x;
        for (cnt=0;x;x/=10) buf[++cnt]=x%10+48;
        while (cnt) print((char)buf[cnt--]);
    }
}
inline void flush(){
	fwrite(obuf,1,ooh-obuf,stdout);
}

void judge(){
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);
}

const int N=110000;
int n,opt;
vector<int> v[N];
map<int,int> M[N];
map<vector<int>,int> H;
set<int> ans;

int dfs(int u,int fa){
	if (M[u].count(fa)) return M[u][fa];
	vector<int> son;
	int t=v[u].size();
	for (int i=0;i<t;i++){
		if (v[u][i]==fa) continue;
		son.push_back(dfs(v[u][i],u));
	}
	sort(son.begin(),son.end());
	if (H.count(son)) return M[u][fa]=H[son];
	return M[u][fa]=H[son]=++opt;
}

int main(){
//	judge();
	read(n);
	for (int i=1;i<n;i++){
		int x,y; read(x),read(y);
		v[x].push_back(y);
		v[y].push_back(x);
	}
	for (int i=1;i<=n;i++){
		if (v[i].size()<4) ans.insert(dfs(i,0));
	}
	print(ans.size()),print('\n');
	return flush(),0;
}

#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")

#include <bits/stdc++.h>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;

#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define F0R(i, a) for (int i = 0; i < (a); i++)
#define FORd(i,a,b) for (int i = (b)-1; i >= (a); i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)
#define trav(a, x) for (auto& a : x)

#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound

#define sz(x) (int)x.size()
#define all(x) begin(x), end(x)
#define rsz resize

const int MOD = 1000000007; // 998244353
const ll INF = 1e18;
const int MX = 200005;
const ld PI = 4*atan((ld)1);

template<class T> void ckmin(T &a, T b) { a = min(a, b); }
template<class T> void ckmax(T &a, T b) { a = max(a, b); }

namespace input {
    template<class T> void re(complex<T>& x);
    template<class T1, class T2> void re(pair<T1,T2>& p);
    template<class T> void re(vector<T>& a);
    template<class T, size_t SZ> void re(array<T,SZ>& a);

    template<class T> void re(T& x) { cin >> x; }
    void re(double& x) { string t; re(t); x = stod(t); }
    void re(ld& x) { string t; re(t); x = stold(t); }
    template<class Arg, class... Args> void re(Arg& first, Args&... rest) {
        re(first); re(rest...);
    }

    template<class T> void re(complex<T>& x) { T a,b; re(a,b); x = cd(a,b); }
    template<class T1, class T2> void re(pair<T1,T2>& p) { re(p.f,p.s); }
    template<class T> void re(vector<T>& a) { F0R(i,sz(a)) re(a[i]); }
    template<class T, size_t SZ> void re(array<T,SZ>& a) { F0R(i,SZ) re(a[i]); }
}

using namespace input;

namespace output {
    template<class T1, class T2> void pr(const pair<T1,T2>& x);
    template<class T, size_t SZ> void pr(const array<T,SZ>& x);
    template<class T> void pr(const vector<T>& x);
    template<class T> void pr(const set<T>& x);
    template<class T1, class T2> void pr(const map<T1,T2>& x);

    template<class T> void pr(const T& x) { cout << x; }
    template<class Arg, class... Args> void pr(const Arg& first, const Args&... rest) {
        pr(first); pr(rest...);
    }

    template<class T1, class T2> void pr(const pair<T1,T2>& x) {
        pr("{",x.f,", ",x.s,"}");
    }
    template<class T> void prContain(const T& x) {
        pr("{");
        bool fst = 1; for (const auto& a: x) pr(!fst?", ":"",a), fst = 0; // const needed for vector<bool>
        pr("}");
    }
    template<class T, size_t SZ> void pr(const array<T,SZ>& x) { prContain(x); }
    template<class T> void pr(const vector<T>& x) { prContain(x); }
    template<class T> void pr(const set<T>& x) { prContain(x); }
    template<class T1, class T2> void pr(const map<T1,T2>& x) { prContain(x); }

    void ps() { pr("\n"); }
    template<class Arg> void ps(const Arg& first) {
        pr(first); ps(); // no space at end of line
    }
    template<class Arg, class... Args> void ps(const Arg& first, const Args&... rest) {
        pr(first," "); ps(rest...); // print w/ spaces
    }
}

using namespace output;

namespace io {
    void setIn(string s) { freopen(s.c_str(),"r",stdin); }
    void setOut(string s) { freopen(s.c_str(),"w",stdout); }
    void setIO(string s = "") {
        ios_base::sync_with_stdio(0); cin.tie(0); // fast I/O
        if (sz(s)) { setIn(s+".in"), setOut(s+".out"); } // for USACO
    }
}

using namespace io;

template<class T> T invGeneral(T a, T b) {
    a %= b; if (a == 0) return b == 1 ? 0 : -1;
    T x = invGeneral(b,a);
    return x == -1 ? -1 : ((1-(ll)b*x)/a+b)%b;
}

template<class T> struct modular {
    T val;
    explicit operator T() const { return val; }
    modular() { val = 0; }
    template<class U> modular(const U& v) {
        val = (-MOD <= v && v <= MOD) ? v : v % MOD;
        if (val < 0) val += MOD;
    }
    friend ostream& operator<<(ostream& os, const modular& a) { return os << a.val; }
    friend bool operator==(const modular& a, const modular& b) { return a.val == b.val; }
    friend bool operator!=(const modular& a, const modular& b) { return !(a == b); }

    modular operator-() const { return modular(-val); }
    modular& operator+=(const modular& m) { if ((val += m.val) >= MOD) val -= MOD; return *this; }
    modular& operator-=(const modular& m) { if ((val -= m.val) < 0) val += MOD; return *this; }
    modular& operator*=(const modular& m) { val = (ll)val*m.val%MOD; return *this; }
    friend modular exp(modular a, ll p) {
        modular ans = 1; for (; p; p /= 2, a *= a) if (p&1) ans *= a;
        return ans;
    }
    friend modular inv(const modular& a) {
        auto i = invGeneral(a.val,MOD); assert(i != -1);
        return i;
    } // equivalent to return exp(b,MOD-2) if MOD is prime
    modular& operator/=(const modular& m) { return (*this) *= inv(m); }

    friend modular operator+(modular a, const modular& b) { return a += b; }
    friend modular operator-(modular a, const modular& b) { return a -= b; }
    friend modular operator*(modular a, const modular& b) { return a *= b; }

    friend modular operator/(modular a, const modular& b) { return a /= b; }
};

typedef modular<int> mi;
typedef pair<mi,mi> pmi;
typedef vector<mi> vmi;
typedef vector<pmi> vpmi;

int n,sub[MX],sub2[MX];
vi adj[MX];
map<vi,int> m;
set<int> ans;

int get(vi v) {
	sort(all(v));
	if (!m.count(v)) {
		int nex = sz(m)+1;
		m[v] = nex;
	}
	return m[v];
}

void dfs(int a, int b) {
	vi v;
	trav(t,adj[a]) if (t != b) {
		dfs(t,a);
		v.pb(sub[t]);
	}
	sub[a] = get(v);
}

void dfs2(int a, int b) {
	trav(t,adj[a]) if (t != b) {
		vi v;
		trav(T,adj[a]) if (T != t && T != b) v.pb(sub[T]);
		if (sub2[a]) v.pb(sub2[a]);
		sub2[t] = get(v);
		dfs2(t,a);
	}
	vi v; trav(T,adj[a]) if (T != b) v.pb(sub[T]);
	if (sub2[a]) v.pb(sub2[a]);
	assert(m[{}] == 1);
	if (sz(v) < 4) {
		v.pb(1);
		ans.insert(get(v));
	}
}

int main() {
    setIO(); re(n);
    F0R(i,n-1) {
    	int u,v; re(u,v);
    	adj[u].pb(v), adj[v].pb(u);
    }
    dfs(1,0); dfs2(1,0);
    // FOR(i,1,n+1) ps(i,sub[i],sub2[i]);
    ps(sz(ans));
}

/* stuff you should look for
    * int overflow, array bounds
    * special cases (n=1?), set tle
    * do smth instead of nothing and stay organized
*/

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PL;
const ll mod=1e9+7;
ll mult[2],randNum[100010];
ll hashV[2][100010],rootHash[2][100010],tmpHash[100010];
set<PL> dic;
int size[100010];
vector<int> g[100010];
vector<ll> nxtHash[100010];
mt19937 ran(time(nullptr));
inline bool cmp(int a,int b){
	return hashV[0][a]<hashV[0][b];
}
inline bool cmp2(int a,int b){
	return tmpHash[a]<tmpHash[b];
}
inline ll pow2(ll a,ll b){
	a%=mod;
	ll res=1;
	while(b>0){
		if(b&1) res=res*a%mod;
		b>>=1;
		a=a*a%mod;
	}
	return res;
}
void dfs(int u,int fa){
	size[u]=1;
	for(int v:g[u]){
		if(v==fa) continue;
		dfs(v,u);
		size[u]+=size[v];
	}
	sort(g[u].begin(),g[u].end(),cmp);
	hashV[0][u]=randNum[(int)g[u].size()];
	for(int v:g[u]){
		if(v==fa) continue;
		hashV[0][u]=hashV[0][u]*pow2(mult[0],size[v])%mod;
		hashV[0][u]=(hashV[0][u]+hashV[0][v])%mod;
	}
}
void dfs2(int u,int fa,ll upHash,int upSize){
	for(int v:g[u]){
		if(v!=fa) tmpHash[v]=hashV[0][v];
		else tmpHash[v]=upHash;
	}
	sort(g[u].begin(),g[u].end(),cmp2);
	rootHash[0][u]=randNum[(int)g[u].size()];
	for(int v:g[u]){
		if(v==fa) rootHash[0][u]=rootHash[0][u]*pow2(mult[0],upSize)%mod;
		else rootHash[0][u]=rootHash[0][u]*pow2(mult[0],size[v])%mod;
		rootHash[0][u]=(rootHash[0][u]+tmpHash[v])%mod;
	}
	nxtHash[u].clear();
	for(int v:g[u]){
		if(v!=fa){
			ll nxt=randNum[(int)g[u].size()];
			for(int nxtv:g[u]){
				if(nxtv==v) continue;
				if(nxtv==fa) nxt=nxt*pow2(mult[0],upSize)%mod;
				else nxt=nxt*pow2(mult[0],size[nxtv])%mod;
				nxt=(nxt+tmpHash[nxtv])%mod;
			}
			nxtHash[u].push_back(nxt);
		}
	}
	int idx=0;
	for(int v:g[u]){
		if(v!=fa){
			dfs2(v,u,nxtHash[u][idx++],upSize+size[u]-size[v]);
		}
	}
}
int main(){
	int n,a,b;
	scanf("%d",&n);
	mult[0]=ran()%mod;
	mult[1]=ran()%mod;
	for(int i=1;i<n;i++){
		scanf("%d%d",&a,&b);
		g[a].push_back(b);
		g[b].push_back(a);
		randNum[i]=ran()%mod;
	}
	dfs(1,-1);
	dfs2(1,-1,0,0);
	for(int i=1;i<=n;i++){
		swap(rootHash[0][i],rootHash[1][i]);
		swap(hashV[0][i],hashV[1][i]);
	}
	swap(mult[0],mult[1]);
	dfs(1,-1);
	dfs2(1,-1,0,0);
	for(int i=1;i<=n;i++)
		if((int)g[i].size()<4)
			dic.insert(PL(rootHash[0][i],rootHash[1][i]));
	printf("%d\n",(int)dic.size());
	return 0;
}

#include <bits/stdc++.h>
#define sqr3(a) ((a)*(a)*(a))
using namespace std;
typedef long long ll;
const int N=100005;
const int P1=998244353;
const int P2=1000000007;
const int K=233333;
int n,x,y,cnt,ans,head[N],ee[N];
struct HASH{ll hash1,hash2;}vv;
map<int,HASH> h[N];
bool operator<(HASH a,HASH b){
	return a.hash1==b.hash1?a.hash2<b.hash2:a.hash1<b.hash1;
}
map<HASH,bool> vis;
struct edge{int to,nt;}e[N*2];
void add(int x,int y){
	e[++cnt]=(edge){y,head[x]};
	head[x]=cnt;
}
void dfs(int x,int fa){
	if(h[x][fa].hash1>0)return;
	HASH res=(HASH){K,K};
	for(int i=head[x];i;i=e[i].nt){
		int v=e[i].to;
		if(v==fa)continue;
		dfs(v,x);
		res.hash1+=sqr3(h[v][x].hash1)%P1;
		res.hash2+=sqr3(h[v][x].hash2)%P2;
	}
	h[x][fa]=(HASH){res.hash1%P1,res.hash2%P2};
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
		ee[x]++;ee[y]++;
	}
	for(int i=1;i<=n;i++)if(ee[i]<4){
		dfs(i,0);vv=h[i][0];
		if(!vis[vv]){vis[vv]=1;ans++;}
	}
	printf("%d",ans);
	return 0;
}

#include <iostream>
#include <vector>
#include <array>
#include <stdio.h>
#include <ios>
#include <string.h>
#include <algorithm>
#include <functional>

constexpr unsigned primes[]{ 2672090437, 2569161337, 2414657393 };
constexpr int np = sizeof(primes) / sizeof(*primes);

std::vector<std::array<unsigned, np> > pow2;
void setpow2(int maxp) {
	pow2.resize(maxp + 1);
	for (int i = 0; i < np; i++)
		pow2[0][i] = 1;
	for (int i = 1; i <= maxp; i++)
		for (int j = 0; j < np; j++)
			pow2[i][j] = pow2[i - 1][j] * 2ULL % primes[j];
}

struct hash {
	unsigned m[np];
	int nbits;
	hash() {}
	hash(unsigned num, int nbits = 1) : nbits(nbits) {
		for (int i = 0; i < np; i++)
			m[i] = num;
	}
};
hash join(hash a, hash b) {
	hash out;
	out.nbits = a.nbits + b.nbits;
	for (int i = 0; i < np; i++)
		out.m[i] = (a.m[i] * (uint64_t)pow2[b.nbits][i]  + b.m[i]) % primes[i];
	return out;
}
bool operator<(hash a, hash b) {
	if (a.nbits != b.nbits)
		return a.nbits < b.nbits;
	return memcmp(a.m, b.m, sizeof(a.m)) < 0;
}

#define N 100000
int w[N];
std::vector<int> adj[N];
hash h0[N];
hash hnew[N];
int deg[N];

int findw(int v, int par = -1) {
	int t = 1;
	for (int x : adj[v]) {
		if (x != par)
			t += findw(x, v);
	}
	return w[v] = t;
}

void genh0(int v, bool rec = true) {
	if (rec) {
		for (int x : adj[v])
			genh0(x);
	}
	std::sort(adj[v].begin(), adj[v].end(), [](int a, int b) { return h0[a] < h0[b]; });
	hash out(0);
	for (int x: adj[v])
		out = join(out, h0[x]);
	h0[v] = join(out, hash(1));
}

void hconcat(int v, hash h) {
	hnew[v] = memcmp(hnew[v].m, h.m, sizeof(h.m)) < 0 ?
		join(hnew[v], h) : join(h, hnew[v]);
	for (int x : adj[v])
		hconcat(x, h);
}

int main()
{
	std::ios_base::sync_with_stdio(false);
	int n;
	scanf("%d", &n);
	setpow2(2 * n + 5);
	for (int i = n; --i; ) {
		int a, b;
		scanf("%d %d", &a, &b);
		--a; --b;
		adj[a].push_back(b);
		adj[b].push_back(a);
		++deg[a];
		++deg[b];
	}
	findw(0);
	std::vector<int> center;
	for (int i = n; i--;) {
		if (n % 2 == 0 && w[i] == n / 2) {
			for (int j : adj[i]) {
				if (w[j] > w[i]) {
					center = { i, j };
					break;
				}
			}
			break;
		}
		else if (n - w[i] < (n + 1) / 2) {
			bool isC = true;
			for (int v : adj[i])
				isC &= w[v] > w[i] || w[v] < (n + 1) / 2;
			if (isC) {
				center = { i };
				break;
			}
		}
	}
	bool ecent = center.size() == 2;
	for (auto i = center.size(); i--; )
		findw(center[i], center[i ^ +ecent]);

	for (int i = n; i--;) {
		std::sort(adj[i].begin(), adj[i].end(), [](int a, int b) {
			return w[a] < w[b];
		});
		if (n > 1 && (ecent || i != center[0]))
			adj[i].pop_back();
	}

	struct split {
		const int* eqb, *eqe;
		hash pre, post;
	};
	std::vector<split> ss;
	const hash h01 = join(hash(0), hash(1));
	std::function<void(int, hash, hash, int)> genh;
	int nbad = 0;
	genh = [&](int v, hash pre, hash post, int skipw) {
		if (deg[v] < 4) {
			hash h = join(pre, h01);
			for (int x : adj[v])
				h = join(h, h0[x]);
			h = join(h, post);

			for (auto it = ss.crbegin(); it != ss.crend(); ++it) {
				hash hh = it->pre;
				bool inserted = false;
				for (const int* i = it->eqb; i != it->eqe; ++i) {
					if (!inserted && memcmp(h.m, h0[*i].m, sizeof(h.m)) < 0) {
						inserted = true;
						hh = join(hh, h);
					}
					hh = join(hh, h0[*i]);
				}
				if (!inserted)
					hh = join(hh, h);
				h = join(hh, it->post);
			}
			hnew[v] = h;
		} else {
			hnew[v].nbits = -1;
			nbad++;
		}

		for (auto aj = adj[v].cbegin(), ae = adj[v].cend(); aj != ae; ++aj) {
			if (w[*aj] == skipw)
				continue;
			auto a2 = aj;
			do ++a2; while (a2 != ae && w[*a2] == w[*aj]);
			hash pre2 = pre, post2 = post;
			for (auto a = adj[v].cbegin(); a != a2; ++a) {
				if (a != aj)
					pre2 = join(pre2, h0[*a]);
			}
			if (a2 != ae && w[*a2] == w[*aj] + 1) {
				auto a3 = a2;
				do ++a3; while (a3 != ae && w[*a3] == w[*a2]);
				for (auto a = ae; a != a3; )
					post2 = join(h0[*--a], post2);
				ss.push_back(split{ &*a2, &*a2 + (a3 - a2), pre2, post2 });
				genh(*aj, hash(0), hash(1), -1);
				ss.pop_back();
			} else {
				for (auto a = ae; a != a2; )
					post2 = join(h0[*--a], post2);
				pre2 = join(pre2, hash(0));
				post2 = join(hash(1), post2);
				genh(*aj, pre2, post2, -1);
			}

		}
	};
	if (ecent) {
		genh0(center[0]);
		genh0(center[1]);
		for (int i : {0, 1}) {
			int c = center[i];
			adj[c].push_back(center[i ^ 1]);
			genh(c, hash(0, 0), hash(0, 0), n / 2);
			adj[c].pop_back();
		}
	} else {
		int c = center[0];
		genh0(c);
		genh(c, hash(0, 0), hash(0, 0), n / 2);
		for (auto i = adj[c].size(); i--; ) {
			int c2 = adj[c][i];
			if (w[c2] != n / 2) continue;
			adj[c].erase(adj[c].begin() + i);
			genh0(c, false);
			genh(c2, hash(0, 0), hash(0, 0), -1);
			adj[c].insert(adj[c].begin() + i, c2);
			hconcat(c2, h0[c]);
		}
	}
	std::sort(hnew, hnew + n);
	int ans = 1;
	for (int i = nbad + 1; i < n; i++) {
		if (memcmp(hnew + i, hnew + i - 1, sizeof(*hnew)))
			++ans;
	}
	std::cout << ans;

    return 0;
}

#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
#define Each(i,v)  for(i=v.begin();i!=v.end();i++)
#define r(x)   read(x)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
    if (CH == '-') NEG = true , CH = getchar() ;
    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
    if (NEG) ret = -ret ;
}
#define  maxn  100010LL
#define  pb    push_back
using namespace std;

int n, idx = 0;
int ans[maxn];
vector<int> G[maxn];
map<int,int> R[maxn];
map<int,int>::iterator it;
map<vector<int>,int> H;
map<vector<int>,int>::iterator it2;
set<int> S;

int dp(int u,int fa) {
    if (it=R[u].find(fa), it!=R[u].end()) return it->second;
    vector<int>now; int i;
    rep (i,0,G[u].size())
        if (G[u][i] != fa)
            now.pb(dp(G[u][i],u));
    sort(now.begin(),now.end());
    if (it2=H.find(now), it2==H.end()) return R[u][fa] = H[now] = ++idx;
    else return R[u][fa] = it2->second;
}
int main() {
    int i,n,u,v;
    r(n);
    rep (i,1,n)
        r(u), r(v), G[u].pb(v), G[v].pb(u);
    Rep (i,1,n)
        if (G[i].size() < 4) S.insert(dp(i,0));
    printf("%d\n", S.size());
    END: getchar(), getchar();
    return 0;
}

#include <cstdio>
#include <map>
using namespace std;
#define int long long
const int N=1e5+7,P=1e9+7,Q=1e9+9;
int e[N][5],vis[N][5],ru[N];
int n,ans;
struct has {
	int n1,n2;
	has operator *(has a) const {
		a.n1=a.n1*n1%P;a.n2=a.n2*n2%Q;
		return a;
	}
	has operator +(has a) const {
		a.n1=(a.n1+n1)%P;a.n2=(a.n2+n2)%Q;
		return a;
	}
	bool operator <(has a) const {
		return n1==a.n1?n2<a.n2:n1<a.n1;
	}
}
f[N][5],so,now;
map<has,bool> flg;
has dfs(int x,int fa) {
	int v;
	for (int i=0;i<=4;i++) if (e[x][i]==fa) v=i;
	if (vis[x][v]) return f[x][v];
	has now=(has){1,1};
	for (int i=1;i<=4 && e[x][i];i++) {
		if (e[x][i]==fa) continue;
		so=dfs(e[x][i],x);
		now=now+so*so*so;
	}
	vis[x][v]=1;
	return f[x][v]=now;
}
signed main() {
	scanf("%lld",&n);
	for (int i=1,u,v;i<n;i++) {
		scanf("%lld%lld",&u,&v);
		ru[u]++;ru[v]++;
		e[u][ru[u]]=v;e[v][ru[v]]=u;
	}
	for (int i=1;i<=n;i++)
		if (ru[i]<4) {
			now=dfs(i,0);
			if (!flg[now]) ans++,flg[now]=1;
		}
	printf("%I64d\n",ans);
}

#include <bits/stdc++.h>

using namespace std;

const int maxn = 100005;

set<int> calc;
map<vector<int>,int> has;
map<int,int> sav[maxn];
vector<int> lk[maxn];
int deg[maxn],n,cnt;

int dfs(int now,int pre)
{
	if (sav[now][pre]) return sav[now][pre];
	vector<int> cur;
	for(int i = 0;i < lk[now].size();i ++)
		if (lk[now][i] != pre) cur.push_back(dfs(lk[now][i],now));
	sort(cur.begin(),cur.end());
	if (!has[cur]) has[cur] = ++ cnt;
	return sav[now][pre] = has[cur];
}

int main()
{
	scanf("%d", &n);
	for(int i = 1,u,v;i < n;i ++)
	{
		scanf("%d%d", &u, &v);
		deg[u] ++,deg[v] ++;
		lk[u].push_back(v),lk[v].push_back(u);
	}
	for(int i = 1;i <= n;i ++) if (deg[i] < 4) calc.insert(dfs(i,0));
	printf("%d\n", calc.size());
	return 0;
}

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>

using namespace std;

#define mp make_pair
#define pb push_back
#define ll long long

#define maxN 100011
#define mod 1000000007
#define base 31

int n, i, x, y;
vector<int> list[maxN];
ll dp[maxN];
vector<ll> sol;

int cnt;
map< vector<int>, int > M;

ll compute(int node, int deny) {
    static ll ans;
    static vector<int> aux;

    aux.clear();

    for (auto to : list[node])
        if (deny != to)
            aux.pb(dp[to]);

    sort(aux.begin(), aux.end());
    reverse(aux.begin(), aux.end());

    if (M[aux] == 0) M[aux] = ++cnt;

    return M[aux];
}

void dfs(int node, int root) {

    for (auto to : list[node])
        if (to != root)
            dfs(to, node);

    dp[node] = compute(node, root);
}

void solve(int node, int root) {
    if (list[node].size() < 4)
        sol.pb(compute(node, 0));

    for (auto to : list[node]) {
        if (to == root) continue;
        dp[node] = compute(node, to);
        solve(to, node);
    }

    dp[node] = compute(node, root);
}

int main()
{
    //freopen("test.in","r",stdin);

    scanf("%d", &n);
    for (i = 1; i < n; i++) {
        scanf("%d%d", &x, &y);
        list[x].pb(y);
        list[y].pb(x);
    }

    dfs(1, 0);
    solve(1, 0);

    sort(sol.begin(), sol.end());
    sol.resize(unique(sol.begin(), sol.end()) - sol.begin());

    printf("%d\n", sol.size());

    return 0;
}

#include<cstdio>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
const int N=1e5+5,M=2*N,L=4*N;
map<int,int>f[N];
map<vector<int>,int>has;
struct edge{int l,to;}e[M];
int n,i,et,he[N],deg[N],cnt,ans;
bool have[L];
int read(){
  char c=getchar();int k=0;for (;c<48||c>57;c=getchar());
  for (;c>47&&c<58;c=getchar()) k=(k<<3)+(k<<1)+c-48;return k;
}
void line(int x,int y){
  e[++et].l=he[x];he[x]=et;e[et].to=y;
}
int dfs(int x,int fa){
  if (f[x][fa]) return f[x][fa];
  vector<int>q;int y;
  for (int i=he[x];i;i=e[i].l) if (y=e[i].to,y!=fa)
    q.push_back(dfs(y,x));
  sort(q.begin(),q.end());
  if (!has[q]) has[q]=++cnt;return f[x][fa]=has[q];
}
int main(){
  for (n=read(),i=1;i<n;i++){
    int x=read(),y=read();
    line(x,y);line(y,x);
    deg[x]++;deg[y]++;
  }
  for (i=1;i<=n;i++)
    if (deg[i]<4) have[dfs(i,0)]=1;
  for (i=1;i<=cnt;i++) if (have[i]) ans++;
  printf("%d",ans);
}

#include <cstdio>
#include <vector>
#include <algorithm>
#include <set>

int n;
int head[100001],nxt[200001],b[200001],k,size[100001],mx[100001],root;
int dep[100001];
int f[100001],d[100001],fa[100001];
const int P=1004535809;
int Pow[100001];
void push(int s,int t){
	nxt[++k]=head[s];
	head[s]=k;
	b[k]=t;
}
void getroot(int x,int f){
	size[x]=1,mx[x]=0;
	fa[x]=f;
	for(int i=head[x];i;i=nxt[i])
		if(b[i]!=f){
			getroot(b[i],x);
			size[x]+=size[b[i]];
			mx[x]=std::max(mx[x],size[b[i]]);
		}
	mx[x]=std::max(mx[x],n-size[x]);
	if(mx[x]<mx[root])root=x;
}
int cnt;
int hsh[100001],hsh2[100001];
void dfs1(int x,int f,int *hsh,int P){
	std::vector<int>tem;
	for(int i=head[x];i;i=nxt[i])
		if(b[i]!=f){
			dfs1(b[i],x,hsh,P);
			dep[x]=std::max(dep[x],dep[b[i]]+1);
			tem.push_back(1ll*hsh[b[i]]*1145141%P*Pow[dep[b[i]]+1]%P);
		}
	tem.push_back(1145141);
	std::sort(tem.begin(),tem.end());
	for(int i=0;i<(int)tem.size();i++)
		hsh[x]=((1ll*hsh[x]*Pow[i]%P)+tem[i])%P;
}
void getans(int x,int F){
	std::set<std::pair<int,int> >set;
	f[x]=(d[x]<=3);
	for(int i=head[x];i;i=nxt[i])
		if(b[i]!=F&&!set.count(std::make_pair(hsh[b[i]],hsh2[b[i]]))){
			set.insert(std::make_pair(hsh[b[i]],hsh2[b[i]]));
			getans(b[i],x);
			f[x]+=f[b[i]];
		}
}
int main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	scanf("%d",&n);
	Pow[0]=1;
	for(int i=1;i<=n;i++)Pow[i]=1ll*Pow[i-1]*467324887%P;
	if(n<=2){
		puts("1");
		return 0;
	}
	for(int i=1,u,v;i<n;i++)scanf("%d%d",&u,&v),push(u,v),push(v,u),++d[u],++d[v];
	mx[root=0]=n;
	getroot(1,0);
	if(n%2==0&&mx[root]==(n>>1)){
		int p=fa[root];
		for(int i=head[root];i;i=nxt[i])
			if(size[b[i]]==n>>1)p=b[i];
		dfs1(root,p,hsh,998244353);
		dfs1(root,p,hsh2,1004535809);
		dfs1(p,root,hsh,998244353);
		dfs1(p,root,hsh2,1004535809);
		if(hsh[p]==hsh[root]&&hsh2[p]==hsh2[root]){
			getans(root,p);
			printf("%d\n",f[root]);
		}
		else{
			getans(root,p);
			getans(p,root);
			printf("%d\n",f[root]+f[p]);
		}
	}
	else{
		dfs1(root,0,hsh,998244353);
		dfs1(root,0,hsh2,1004535809);
		getans(root,0);
		printf("%d\n",f[root]);
	}
}

#include<queue>
#include<ctime>
#include<vector>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<memory.h>
#include<map>
#include<ctime>
#include<algorithm>
#include<ctime>
#include<set>
#define ll int
#define For(i,j,k)  for(ll i=j;i<=k;++i)
#define FOr(i,j,k)  for(ll i=j;i>=k;--i)
#define ld double
using namespace std;
inline ll read(){   ll x=0,f=1;char ch=getchar();   while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}  while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}  return x*f; }
inline void wrote(ll x){    if (x<0) putchar('-'),x=-x; if (x>=10) wrote(x/10);   putchar(x%10+'0');  }
inline void writeln(ll x){ wrote(x);   puts("");   }
const ll N=200010;
set<ll>ans;
ll n,tot,head[N],nxt[N],vet[N],dfn[N],cnt;
map<vector<ll>,ll>hsh;
map<ll,ll>mp[N];
void Add(ll x,ll y){	nxt[++tot]=head[x];	head[x]=tot;	vet[tot]=y;	++dfn[x];	}
ll insert(ll x,ll pre){
	if (mp[x][pre])	return mp[x][pre];
	vector<ll>lbc;
	for(ll i=head[x];i;i=nxt[i])
	if (vet[i]!=pre)	lbc.push_back(insert(vet[i],x));
	sort(lbc.begin(),lbc.end());
	if (!hsh[lbc])	hsh[lbc]=++cnt;
	return mp[x][pre]=hsh[lbc];
}
int main(){
	n=read();
	For(i,2,n){
		ll x=read(),y=read();
		Add(x,y);	Add(y,x);
	}
	For(i,1,n)	if (dfn[i]<4)	ans.insert(insert(i,0));
	writeln(ans.size());
}

#include<cstdio>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int N=100100,P1=1000000007,P2=1000000009,T=23333;
int i,j,k,n,m,ch,En,x,y,ans;
int h[N],d[N];
struct edge {int s,n;} E[N<<1];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
struct cc {
	int x1,x2;
	cc operator * (const cc &n) const {
		cc t;
		t.x1=(ll) x1*n.x1%P1;
		t.x2=(ll) x2*n.x2%P2;
		return t;
	}
	cc operator + (const cc &n) const {
		cc t;
		t.x1=(x1+n.x1)%P1;
		t.x2=(x2+n.x2)%P2;
		return t;
	}
	bool operator < (const cc &n) const {
		if (x1==n.x1) return x2<n.x2;
		return x1<n.x1;
	}
} tmp;
map<int,cc> f[N];
set<cc> S;
cc get_hash(int x,int F) {
	if (f[x].find(F)!=f[x].end()) return f[x][F];
	cc t,tt;
	t.x1=t.x2=T;
	for (int k=h[x];k;k=E[k].n) if (E[k].s!=F) {
		tt=get_hash(E[k].s,x);
		t=t+tt*tt*tt;
	}
	return f[x][F]=t;
}
void E_add(int x,int y) {
	d[x]++;d[y]++;
	E[++En].s=y;E[En].n=h[x];h[x]=En;
	E[++En].s=x;E[En].n=h[y];h[y]=En;
}
int main() {
	R(n);
	for (i=1;i<n;i++) {
		R(x);R(y);
		E_add(x,y);
	}
	for (i=1;i<=n;i++) if (d[i]<4) {
		tmp=get_hash(i,0);
		if (S.find(tmp)==S.end()) ans++,S.insert(tmp);
	}
	printf("%d\n",ans);
}

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <map>
#include <ctime>
#include <cmath>
#include <algorithm>
#include <set>
#include <utility>
#include <iomanip>
#include <queue>

using namespace std;

#define FILE "file"
#define N 100100

typedef long long ll;

map< vector<int>, int > m;
set <int> s;
int n, a[N], cnt, b[N], used_b[N];
vector <int> g[N];
vector <int> children[N];

int compute_value(vector<int> &children)	{
	if (children.size() == 0)
		return 0;

	vector <int> values;
	for (int i = 0; i < children.size(); i++)
		values.push_back(a[children[i]]);

	while (values.size() < 4)
		values.push_back(-1);

	sort(values.begin(),values.end());
	if (m.count(values) == 0)
	{
		cnt++;
		m[values] = cnt;
	}
	return m[values];
}

void dfs(int k, int prev=-1)	{

	for (int i = 0; i < g[k].size(); i++)
		if (g[k][i] != prev)
		{
			dfs(g[k][i],k);
			children[k].push_back(g[k][i]);
		}

	a[k] = compute_value(children[k]);
}

void remove_child(vector<int> &children, int num)	{
	for (int i = 0; i < children.size(); i++)
		if (children[i] == num)
			children.erase(children.begin()+i);
}

void push_value(int k, int prev=-1)	{

	b[k] = a[k];

	//cerr << endl;
	//cerr << "value of " << k << " is " << a[k] << endl;

	for (int i = 0; i < g[k].size(); i++)
		if (g[k][i] != prev)
		{
			remove_child(children[k],g[k][i]);

			//cerr << "edge: " << k << ' ' << g[k][i] << endl;
			a[k] = compute_value(children[k]);

			//cerr << "new value of: " << k << " is " << a[k] << endl;
			children[g[k][i]].push_back(k);
			a[g[k][i]] = compute_value(children[g[k][i]]);
			//cerr << "new value of: " << g[k][i] << " is " << a[g[k][i]] << endl;

			push_value(g[k][i],k);

			remove_child(children[g[k][i]],k);
			a[g[k][i]] = compute_value(children[g[k][i]]);
			//cerr << "restore value of: " << g[k][i] << " to " << a[g[k][i]] << endl;

			// for (auto i : children[g[k][i]])
// 				cerr << i << ' ';
// 			cerr << endl;

			children[k].push_back(g[k][i]);
			a[k] = compute_value(children[k]);

			//cerr << "restore value of: " << k << " to " << a[k] << endl;
		}
	//cerr << endl;
}

int main() {

	//freopen (FILE".in", "r", stdin);
	//freopen (FILE".out", "w", stdout);

	cin >> n;
	for (int to, from, i = 1; i < n; i++)
	{
		cin >> from >> to;
		g[from].push_back(to);
		g[to].push_back(from);
	}

	dfs(1);
	push_value(1);

	for (int i = 1; i <= n; i++)
		if (s.count(b[i]) == 0 && g[i].size() < 4)
			s.insert(b[i]);
	cout << s.size() << endl;
	return 0;
}

#include<bits/stdc++.h>
using namespace std;typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f,oo = inf;
#define pi 3.14159265358979323846
#define IL inline
#define RG register
#define rep(i,a,b) for(RG int i=(a);i<int(b);++i)
#define Rep(i,a,b) for(RG int i=(a);i<=(b);++i)
#define Dep(i,a,b) for(RG int i=(a);i>=(b);--i)
#define pc putchar
#define gc getchar
IL ll read(){
    RG ll lson=0;char f=0;RG char c=gc();
    for(;!isdigit(c);c=gc())f|=(c=='-');
    for(;isdigit(c);c=gc())lson=(lson<<1)+(lson<<3)+(c^48);
    return f?-lson:lson;
}
IL void write(ll lson){if(lson<0)lson=-lson,pc('-');if(lson>=10)write(lson/10);pc(lson%10+'0');}
IL void writeln(ll lson){write(lson);puts("");}
IL void writeln(ll lson,char c,ll rson){write(lson);pc(c);writeln(rson);}
IL void writeln(ll lson,char c,ll rson,char d,ll z){write(lson);pc(c);write(rson);pc(d);writeln(z);}
#define debug(lson) printf(#lson" = %d\n",lson);
#define rd() read()
#define rdb() readdb()
#define pb push_back
#define y1 ____y1
#define union _union
const int maxn = 100005;
vector<int> edge[maxn];
int ok[maxn*5];
int n,cnt;
map<vector<int>,int> mp;
map<int,int> f[maxn];
int dfs(int u,int fa){
	vector<int> V;
	if(f[u][fa]) return f[u][fa];
	for(auto v:edge[u]) if(v!=fa)V.push_back(dfs(v,u));
	sort(V.begin(),V.end());
	if(!mp[V]) mp[V]=++cnt;
	return f[u][fa]=mp[V];
}
int main(){
	n = rd(),cnt=0;
	rep(i,1,n){
		int x = rd(),y = rd();
		edge[x] . push_back(y);
		edge[y] . push_back(x);
	}
	Rep(i,1,n)
		if(edge[i].size() < 4)
			ok[dfs(i,0)] = true;
	int ans=0;
	Rep(i,1,cnt) if(ok[i]) ans++;
	writeln(ans);
	return 0;
}

//尽人事，听天命。明天会更好。--myc
#include<cstdio>
#include<cstring>
#include<iostream>
#include<stdlib.h>
#include<ctime>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define LL long long
#define FOR(i,a,b) for (int i=a;i<=b;i++)
#define FORD(i,a,b) for (int i=a;i>=b;i--)
using namespace std;
typedef pair<int,int> pa;
void getint(int &v){
    char ch,fu=0;
    for(ch='*'; (ch<'0'||ch>'9')&&ch!='-'; ch=getchar());
    if(ch=='-') fu=1, ch=getchar();
    for(v=0; ch>='0'&&ch<='9'; ch=getchar()) v=v*10+ch-'0';
    if(fu) v=-v;
}
set<int> S;
map<int,int> M[100010];
map<vector<int>,int> H;
int nedge,nxt[500010],n,d[500010],x,y,cnt,hed[500010],too[500010];
void ae(int x,int y){
	nxt[++nedge]=hed[x];
	hed[x]=nedge;
	too[nedge]=y;
}
int dfs(int x,int l){
	if (M[x].find(l)!=M[x].end()) return M[x][l];
	vector<int> v;
	for (int i=hed[x];i;i=nxt[i]){
		int y=too[i];
		if (y==l) continue;
		v.pb(dfs(y,x));
	}
	sort(v.begin(),v.end());
	if (H.find(v)==H.end()) H[v]=++cnt;
	return M[x][l]=H[v];
}
int main(){
	scanf("%d",&n);
	FOR(i,2,n){
		scanf("%d%d",&x,&y);
		ae(x,y),ae(y,x);
		++d[x],++d[y];
	}
	FOR(i,1,n) if (d[i]<4) S.insert(dfs(i,0));
	cout<<S.size()<<endl;
	return 0;
}

#include<bits/stdc++.h>
#define ll long long
#define X first
#define Y second
#define MP make_pair
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;

const int maxn = 1e5+10;
int n,a[maxn],b[maxn],au[maxn][10],cnt,du[maxn];
vector<int> g[maxn],li;
map<vector<int>,int> M;

void solve(vector<int> &a,int &b){
    while(a.size()<4) a.push_back(-1);
    sort(a.begin(),a.end());
    if(!M.count(a)) b=M[a]=++cnt;
    else b=M[a];
}

void dfs(int u,int fa){
    vector<int> c;
    c.clear();
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];
        if(v==fa) continue;
        dfs(v,u);
        c.push_back(a[v]);
    }
    solve(c,a[u]);
}

void dfs2(int u,int fa,int id){
    vector<int> c,cc;
    cc.clear();
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];
        if(v==fa) continue;
        cc.push_back(a[v]);
        c.clear();
        if(fa) c.push_back(au[fa][id]);
        for(int j=0;j<g[u].size();j++){
            int v=g[u][j];
            if(v==fa||j==i) continue;
            c.push_back(a[v]);
        }
        solve(c,au[u][i]);
    }
    if(fa) cc.push_back(au[fa][id]);
    solve(cc,b[u]);
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];
        if(v==fa) continue;
        dfs2(v,u,i);
    }
}

int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    scanf("%d",&n);
    for(int i=2;i<=n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        g[u].push_back(v),g[v].push_back(u);
        du[u]++,du[v]++;
    }
    dfs(1,0);
    dfs2(1,0,-1);
    for(int i=1;i<=n;i++)
        if(du[i]<4) li.push_back(b[i]);
    sort(li.begin(),li.end());
    li.erase(unique(li.begin(),li.end()),li.end());
    printf("%d\n",(int)li.size());
    return 0;
}

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

const int mo[3]={998244353,1000000007,1000000009};
const int K[3]={137,1003,997};
const int maxn=100003;

int f[maxn][3],g[maxn][3],head[maxn],deg[maxn],n;

struct EDGE{
	int to,nxt;
}edge[maxn<<1];
void addedge(int u,int v){
	static int sz=0;edge[++sz].to=v;
	edge[sz].nxt=head[u];head[u]=sz;
}

void dfs(int u,int pre=0){
	int to;
	for(int i=0;i<3;++i)f[u][i]=1;
	for(int i=head[u];i;i=edge[i].nxt){
		to=edge[i].to;
		if(to==pre) continue;
		dfs(to,u);
		for(int j=0;j<3;++j)
			f[u][j]=(f[u][j]+1ll*f[to][j]*f[to][j]%mo[j]*K[j]%mo[j])%mo[j];
	}
}

void dfs1(int u,int pre=0){
	int to;
	for(int i=head[u];i;i=edge[i].nxt){
		to=edge[i].to;
		if(to==pre) continue;
		for(int j=0;j<3;++j){
			g[to][j]=(g[u][j]-1ll*f[to][j]*f[to][j]%mo[j]*K[j]%mo[j])%mo[j];
			g[to][j]=1ll*g[to][j]*g[to][j]%mo[j]*K[j]%mo[j];
			g[to][j]=(g[to][j]+f[to][j])%mo[j];
			g[to][j]=(g[to][j]+mo[j])%mo[j];
		}
		dfs1(to,u);
	}
}

set<pair<int,pair<int,int> > > used;

int main(){
	scanf("%d",&n);
	for(int i=1;i<n;++i){
		static int u,v;
		scanf("%d%d",&u,&v);
		addedge(u,v);
		addedge(v,u);
		++deg[u];++deg[v];
	}
	dfs(1);
	for(int j=0;j<3;++j)
		g[1][j]=f[1][j];
	dfs1(1);
	for(int i=1;i<=n;++i){
//		printf("%d %d %d\n",g[i][0],g[i][1],g[i][2]);
		if(deg[i]<4)
			used.insert(make_pair(g[i][0],make_pair(g[i][1],g[i][2])));
	}
	printf("%d\n",used.size());
	return 0;
}

#include<bits/stdc++.h>
#define Ll long long
using namespace std;
inline Ll RR(){Ll v=0,k=1;char c=0;while('0'>c||c>'9'){if(c=='-')k=-1;c=getchar();}while('0'<=c&&c<='9')v=v*10+c-48,c=getchar();return v*k;}
inline void W(Ll x){if(x<0)putchar('-'),x=-x;if(x>9)W(x/10);putchar(x%10+48);}
inline void WW(Ll x){W(x);puts("");}
inline void read(int &x,int &y){x=RR();y=RR();}
const int N=1e5+5;
map<vector<int>,int>F;
map<int,int>f[N];
vector<int>h[N];
bool ok[N*5];
int n,m,x,y,ans,cnt,A[N];
int dfs(int x,int y){
	if(f[x][y])return f[x][y];
	vector<int> V;
	for(int k=0;k<h[x].size();k++)
		if(h[x][k]!=y)V.push_back(dfs(h[x][k],x));
	sort(V.begin(),V.end());
	if(!F[V])F[V]=++cnt;
	return f[x][y]=F[V];
}
int main()
{
	n=RR();
	for(int i=1;i<n;i++){
		read(x,y);
		h[x].push_back(y);
		h[y].push_back(x);
		A[x]++;A[y]++;
	}
	for(int i=1;i<=n;i++)
		if(A[i]!=4)ok[dfs(i,0)]=1;
	for(int i=1;i<=cnt;i++)ans+=ok[i];
	W(ans);
}

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
#include <set>
using namespace std;
const int N = 1e5+5;

int n, m;
vector<int> e[N];
map<vector<int>, int> mp;
map<int, int> f[N];
set<int> s;

int dp(int u, int fa) {
	if(f[u][fa]) return f[u][fa];
	vector<int> cur;
	for(int i=0; i<e[u].size(); i++)
		if(e[u][i] != fa) cur.push_back(dp(e[u][i], u));
	sort(cur.begin(), cur.end());
	if(!mp[cur]) mp[cur] = ++m;
	return f[u][fa] = mp[cur];
}
int main() {
	//freopen("in", "r", stdin);
	ios::sync_with_stdio(false); cin.tie(); cout.tie();

	cin >> n;
	for(int i=1; i<n; i++) {
		int u, v;
		cin >> u >> v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	for(int i=1; i<=n; i++) if(e[i].size() < 4) s.insert(dp(i, 0));
	cout << s.size();
}

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define _for(i, a, b) for (register int i = a; i < b; ++i)
#define _rep(i, a, b) for (register int i = a; i <= b; ++i)
const int ri_top = 1e7;
char ri[ri_top + 1], *rich = ri, *rr = ri;
inline void rd() {*(rr = ri + fread(rich = ri, 1, ri_top, stdin)) = 0;}
inline char nch() {if (++rich >= rr) rd(); return *rich;}
inline void read_int(int& x) {while (!isdigit(*rich)) nch(); for (x = *rich - '0'; isdigit(nch()); x = x * 10 + *rich - '0');}
std::vector<int> G[100001];
__gnu_pbds::tree<int, __gnu_pbds::null_type> S;
__gnu_pbds::tree<int, int>dp[100001]; //记忆化
__gnu_pbds::tree<int, int>::iterator it;
__gnu_pbds::tree<std::vector<int>, int>l; //hash映射到id
__gnu_pbds::tree<std::vector<int>, int>::iterator it1;
int cnt;
int dfs(const int& u, const int& fa)
{
    if ((it = dp[u].find(fa)) != dp[u].end()) return it->second; //记忆化
    std::vector<int> V;
    for (auto i : G[u]) if (i != fa) V.push_back(dfs(i, u));
    std::sort(V.begin(), V.end()); //将子树的hash值拼接起来并排序
    return dp[u][fa] = (((it1 = l.find(V)) != l.end()) ? it1->second : (l[V] = ++cnt)); //判断是否需要新建一个映射并返回
}
int n, u, v;
int main()
{
    read_int(n);
    _for(i, 1, n) {read_int(u); read_int(v); G[u].push_back(v); G[v].push_back(u);}
    _rep(i, 1, n) if (G[i].size() < 4) S.insert(dfs(i, 0)); //不能忽略对度数的判断. 只有连有氢原子的碳原子才可以被取代(仿佛不能说碳原子被取代那就是不能作为根)
    printf("%d\n", S.size()); //不同的hash值的个数.
}

#include <bits/stdc++.h>
#define LL long long
#define pii pair <LL, LL>
#define xx first
#define yy second
using namespace std;

const int N = 100100;
const LL A1 = 23, B1 = 17, C1 = 233, D1 = 19, mod1 = 1e9 + 7;
const LL A2 = 233, B2 = 19, C2 = 29, D2 = 23, mod2 = 1e9 + 9;

map <pii, pii> mp;
vector <int> g[N];
int u[N], v[N];

pii dfs (int u, int fa) {
    if (mp.find (pii (u, fa)) != mp.end()) return mp[pii (u, fa)];
    vector <pii> tmp;
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if (v == fa) continue;
        tmp.push_back (dfs (v, u));
    }
    sort (tmp.begin(), tmp.end());
    LL h1 = g[u].size(), h2 = g[u].size();
    for (int i = 0; i < tmp.size(); i++) {
        h1 = ((h1 * A1) ^ tmp[i].xx) % mod1;
        h2 = ((h2 * A2) ^ tmp[i].yy) % mod2;
//        h1 = (((h1 * A1 + B1) ^ tmp[i].xx) + C1) % mod1;
//        h2 = (((h2 * A2 + B2) ^ tmp[i].yy) + C2) % mod2;
    }
//    (h1 += B1) %= mod1;
//    (h2 += B2) %= mod2;
    (h1 *= D1) %= mod1;
    (h2 *= D2) %= mod2;
//    cout << u << ' ' << fa << ' ' << h1 << ' ' << h2 << endl;
    return mp[pii (u, fa)] = pii (h1, h2);
}

int main () {
//    freopen ("in", "r", stdin);
    int n;
    cin >> n;
    for (int i = 1; i < n; i++) {
        scanf ("%d%d", &u[i], &v[i]);
        g[u[i]].push_back (v[i]);
        g[v[i]].push_back (u[i]);
    }
    set <pii> st;
    for (int i = 1; i <= n; i++) {
        if (g[i].size() < 4) st.insert (dfs (i, 0));
//        cout << dfs (i, 0).xx << ' ' << dfs (i, 0).yy << endl;
//        if (g[v[i]].size() < 4) st.insert (dfs (v[i], u[i]));
    }
    cout << st.size() << endl;
}

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>

const int N = 100000;

int head[N], to[N << 1], next[N << 1], tree_hash[N << 1];
std::map<std::vector<int>, int> hashes;

int get_hash(const std::vector<int>& hash)
{
    if (!hashes.count(hash)) {
        auto count = hashes.size();
        hashes[hash] = count;
    }
    return hashes[hash];
}

int get_tree_hash(int edge)
{
    int& ref = tree_hash[edge];
    if (ref == -1) {
        std::vector<int> hashes;
        for (int iterator = head[to[edge]]; ~iterator; iterator = next[iterator]) {
            if (to[iterator] != to[edge ^ 1]) {
                hashes.push_back(get_tree_hash(iterator));
            }
        }
        std::sort(hashes.begin(), hashes.end());
        ref = get_hash(hashes);
    }
    return ref;
}

int main()
{
#ifdef LOCAL_JUDGE
    freopen("D.in", "r", stdin);
#endif
    int n;
    while (scanf("%d", &n) == 1) {
        for (int i = 0; i < n - 1 << 1; ++ i) {
            scanf("%d", to + i);
            to[i] --;
        }
        memset(head, -1, sizeof(*head) * n);
        for (int i = 0; i < n - 1 << 1; ++ i) {
            auto& h = head[to[i ^ 1]];
            next[i] = h;
            h = i;
        }
        memset(tree_hash, -1, sizeof(*tree_hash) * (n << 1));
        std::vector<std::vector<int>> hashes;
        for (int u = 0; u < n; ++ u) {
            std::vector<int> hash;
            for (int iterator = head[u]; ~iterator; iterator = next[iterator]) {
                hash.push_back(get_tree_hash(iterator));
            }
            if (static_cast<int>(hash.size()) < 4) {
                std::sort(hash.begin(), hash.end());
                hashes.push_back(hash);
            }
        }
        std::sort(hashes.begin(), hashes.end());
        hashes.erase(std::unique(hashes.begin(), hashes.end()), hashes.end());
        printf("%d\n", static_cast<int>(hashes.size()));
    }
}

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 100010;

int n;
int cnt;

int dp[MAXN];

vector< int > adj[MAXN];
vector< int > values[MAXN];

set< int > rootHashs;

map< vector<int> , int > hashs;

int getHash(vector<int> aux)
{
	if( hashs[ aux ] == 0 )
		hashs[ aux ] = ++cnt;

	return hashs[ aux ];
}

void DFSCalculate(int cur, int p)
{
	for(int i = 0 ; i < adj[cur].size() ; i++)
	{
		int viz = adj[cur][i];

		if( viz == p ) continue;

		DFSCalculate( viz , cur );

		values[cur].push_back( dp[viz] );
	}

	sort( values[cur].begin() , values[cur].end() );

	dp[ cur ] = getHash( values[cur] );
}

void remove(int cur, int v)
{
	for(int i = 0 ; i < values[cur].size() ; i++)
	{
		if( values[cur][i] == v )
		{
			values[cur].erase( values[cur].begin() + i );
			return;
		}
	}
}

void DFSRotate(int cur, int p)
{
	if( adj[cur].size() <= 3 ) rootHashs.insert( dp[cur] );

	for(int i = 0 ; i < adj[cur].size() ; i++)
	{
		int viz = adj[cur][i];

		if( viz == p ) continue;

		int oldDPCur = dp[cur];
		int oldDPViz = dp[viz];

		remove( cur , dp[viz] );
		dp[cur] = getHash( values[cur] );

		values[ viz ].push_back( dp[cur] );
		sort( values[viz].begin() , values[viz].end() );

		dp[viz] = getHash( values[viz] );

		DFSRotate( viz , cur );

		remove( viz , dp[cur] );
		dp[ viz ] = oldDPViz;

		values[ cur ].push_back( dp[viz] );
		sort( values[cur].begin() , values[cur].end() );

		dp[ cur ] = oldDPCur;
	}
}

int main()
{
	scanf("%d",&n);

	for(int i = 1 ; i < n ; i++)
	{
		int U, V;
		scanf("%d %d",&U,&V);

		adj[ U ].push_back( V );
		adj[ V ].push_back( U );
	}

	DFSCalculate( 1 , 1 );
	DFSRotate( 1 , 1 );

	printf("%d\n",(int) rootHashs.size());
}

#include<bits/stdc++.h>
#define N 100005
using namespace std;
int n,m,tot;
vector<int>e[N];
map<vector<int>,int>h;
map<int,int>f[N];
set<int>s;
inline void addEdge(int u,int v){e[u].push_back(v);}
inline int R()
{
    char c;int res,sign=1;
    while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1;res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    return res*sign;
}
inline void write(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>=10)write(x/10);
    putchar(x%10+'0');
}
int dfs(int u,int fa)
{
	vector<int>rec;if(f[u][fa])return f[u][fa];
	for(int v:e[u]){if(v==fa)continue;rec.push_back(dfs(v,u));}
	sort(rec.begin(),rec.end());if(!h[rec])h[rec]=++tot;return f[u][fa]=h[rec];
}
int main()
{
	n=R();for(int i=1,u,v;i<n;i++)u=R(),v=R(),addEdge(u,v),addEdge(v,u);
	for(int i=1;i<=n;i++)if(e[i].size()<4)s.insert(dfs(i,0));
	write(s.size());
}

#include<bits/stdc++.h>
#define eps 1e-10
#define inf 1e9
#define For(i,j,k)	for(int i=j;i<=k;++i)
#define Dow(i,j,k)	for(int i=k;i>=j;--i)
#define ll long long
using namespace std;
inline ll read()
{
	ll t=0,f=1;char c=getchar();
	while(c<'0'||c>'9')	{if(c=='-')	f=-1;c=getchar();}
	while(c>='0'&&c<='9')	t=t*10+c-48,c=getchar();
	return t*f;
}
map<vector<int>,int> hav;
bool mp[2000001];
int n,deg[2000001],ans,x,y;
map<int,int> jy[200001];
int f[2000001],nxt[2000001],poi[2000001],cnt,tot;
inline void add(int x,int y){poi[++cnt]=y;nxt[cnt]=f[x];f[x]=cnt;}
inline int dfs(int x,int fa)
{
	if(jy[x][fa])	return jy[x][fa];
	vector<int> tmp;
	for(int i=f[x];i;i=nxt[i])
	{
		if(poi[i]==fa)	continue;
		tmp.push_back(dfs(poi[i],x));
	}
	sort(tmp.begin(),tmp.end());
	if(!hav[tmp])	hav[tmp]=++tot;
	return jy[x][fa]=hav[tmp];
}
int main()
{
	scanf("%d",&n);
	For(i,1,n-1)
	{
		scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
		deg[x]++;deg[y]++;
	}
	For(i,1,n)	if(deg[i]<4)	mp[dfs(i,0)]=1;
	For(i,1,tot)	if(mp[i])	ans++;
	printf("%d\n",ans);
}

#include <bits/stdc++.h>
using namespace std;
#define PB push_back
#define ZERO (1e-10)
#define INF (1<<29)
#define CL(A,I) (memset(A,I,sizeof(A)))
#define DEB printf("DEB!\n");
#define D(X) cout<<"  "<<#X": "<<X<<endl;
#define EQ(A,B) (A+ZERO>B&&A-ZERO<B)
typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef vector<ii> vii;
#define IN(n) int n;scanf("%d",&n);
#define FOR(i, m, n) for (int i(m); i < n; i++)
#define REP(i, n) FOR(i, 0, n)
#define F(n) REP(i, n)
#define FF(n) REP(j, n)
#define FT(m, n) FOR(k, m, n)
#define aa first
#define bb second
void ga(int N,int *A){F(N)scanf("%d",A+i);}
#define M1 (1000000007)
#define M2 (1000000009)
#define B1 (257ll)
#define B2 (13ll)
#define MX (100009)
vi g[MX];
void dw(int u,int p,int d,int *D){
    D[u]=d;
    for(auto i:g[u])if(i^p)dw(i,u,d+1,D);
}
ii ctr(int N,int r=0){
    static int D[MX],U[MX];
    int d(0),l(-1);
    dw(r,-1,0,D),dw(max_element(D,D+N)-D,-1,0,D);
    dw(l=max_element(D,D+N)-D,-1,0,U);
    d=D[l]>>1;
    if(!(D[l]&1))F(N)if(D[i]==U[i]&&D[i]==d)return {i,-1};
    ii B;
    F(N)if(D[i]==d&&U[i]==d+1)B.bb=i;
    else if(D[i]==d+1&&U[i]==d)B.aa=i;
    return B;
}
unordered_map<int,ll> dp[MX];
ll gh(int u,int p){
    if(dp[u].count(p))return dp[u][p];
    ll a=10000141,b=1234577,S=0;
    vi Z;
    for(auto&h:g[u])if(h^p)Z.PB(gh(h,u));
    sort(Z.begin(),Z.end());
    for(auto&h:Z)S*=a,S+=h,a*=b;
    return dp[u][p]=S*a+1;
}
int dfs(int u,int p){
    set<ll> T;
    int S=g[u].size()<4u;
    for(auto&h:g[u])if(h^p&&!T.count(gh(h,u)))T.insert(gh(h,u)),S+=dfs(h,u);
    return S;
}
int S,N,a,b;
int main(void){
    scanf("%d",&N);
    if(N==1)return puts("1"),0;
    F(N-1)scanf("%d%d",&a,&b),g[--a].PB(--b),g[b].PB(a);
    ii w=ctr(N);
    S=dfs(w.aa,-1);
    if(~w.bb&&gh(w.aa,-1)==gh(w.bb,-1))S-=dfs(w.bb,w.aa);
    printf("%d\n",S);
    return 0;
}

/* Author haleyk10198 */
/* ?@??:  haleyk10198 */
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#define MOD 1000000007
#define LINF (1LL<<60)
#define INF 2147483647
#define PI 3.1415926535897932384626433
#define ll long long
#define pii pair<int,int>
#define mp(x,y) make_pair((x),(y))

using namespace std;
using namespace __gnu_pbds;

map<vector<int>, int> m1,res;

vector<int> near[100010];
vector<int> hh[100010];
int n;

void dfs(int now,int p){
	for(int x:near[now])
		if(x-p){
			dfs(x,now);
			hh[now].push_back(m1[hh[x]]);
		}
	while(hh[now].size()<4)
		hh[now].push_back(-1);
	sort(hh[now].begin(),hh[now].end());
	if(!m1.count(hh[now]))
		m1[hh[now]]=m1.size();
}

void move(int u,int v){
	hh[u].erase(lower_bound(hh[u].begin(),hh[u].end(),m1[hh[v]]));
	hh[u].insert(hh[u].begin(),-1);
	if(!m1.count(hh[u]))
		m1[hh[u]]=m1.size();
	hh[v].erase(hh[v].begin());
	hh[v].push_back(m1[hh[u]]);
	sort(hh[v].begin(),hh[v].end());
	if(!m1.count(hh[v]))
		m1[hh[v]]=m1.size();
}

void solve(int now,int p){
	if(near[now].size()<4)
		res[hh[now]]++;
	for(int x:near[now])
		if(x-p){
			move(now,x);
			solve(x,now);
			move(x,now);
		}
}

int main(){
	//freopen("input.txt","r",stdin);
	//freopen("output.txt","w",stdout);
	ios_base::sync_with_stdio(false);
	cin>>n;
	for(int i=1,u,v;i<n;i++){
		cin>>u>>v;
		--u,--v;
		near[u].push_back(v);
		near[v].push_back(u);
	}
	dfs(0,0);
	solve(0,0);
	cout<<res.size()<<endl;
	return 0;
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
typedef unsigned long long wolf;
vector<int>g[110000];
wolf key[110000];
int st[110000];
int ra[110000];
wolf ran[]={114514,1919810,364364,4545334};
int n;
const long long M=1000000009;
int dfs(int a,int b){
	int rem=n-1;
	for(int i=0;i<g[a].size();i++){
		if(g[a][i]==b)continue;
		int tmp=dfs(g[a][i],a);
		ra[a]=max(ra[a],tmp);
		rem-=tmp;
		st[a]+=tmp;
	}
	ra[a]=max(ra[a],rem);
	st[a]++;
	return st[a];
}
vector<int>gp;
wolf calc(int a,int b){
	vector<wolf> ch;
	for(int i=0;i<g[a].size();i++){
		if(g[a][i]==b)continue;
		ch.push_back(calc(g[a][i],a));
	}
	std::sort(ch.begin(),ch.end());
	wolf ret=ch.size()+1;
	for(int i=0;i<ch.size();i++){
		ret=(ret*mod+ch[i]*ran[i])%M;
	}
	key[a]=ret;
	return ret;
}
int ans;
void cnt(int a,int b){
	if(g[a].size()<4){
		ans++;
	}
	vector<pair<wolf,int> > v;
	for(int i=0;i<g[a].size();i++){
		if(g[a][i]==b)continue;
		v.push_back(make_pair(key[g[a][i]],g[a][i]));
	}
	std::sort(v.begin(),v.end());
	for(int i=0;i<v.size();i++){
		if(i==0||v[i].first!=v[i-1].first){
			cnt(v[i].second,a);
		}
	}
}
int main(){
	int a;scanf("%d",&a);
	for(int i=0;i<a-1;i++){
		int p,q;scanf("%d%d",&p,&q);p--;q--;
		g[p].push_back(q);g[q].push_back(p);
	}
	n=a;
	dfs(0,-1);
	int mv=999999999;
	//for(int i=0;i<a;i++)printf("%d\n",ra[i]);
	for(int i=0;i<a;i++)mv=min(mv,ra[i]);
	for(int i=0;i<a;i++)if(ra[i]==mv)gp.push_back(i);

	if(gp.size()>2){
		printf("yabai\n");while(1);
	}else if(gp.size()==2){
		calc(gp[0],gp[1]);
		calc(gp[1],gp[0]);
		cnt(gp[0],gp[1]);
		if(key[gp[0]]!=key[gp[1]])cnt(gp[1],gp[0]);
	}else{
		calc(gp[0],-1);
		cnt(gp[0],-1);
	}
	printf("%d\n",ans);
}

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define uint unsigned
#define pii pair<int,int>
#define pll pair<ll,ll>
#define IT iterator
#define PB push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define CLR(a,v) memset(a,v,sizeof(a));
#define CPY(a,b) memcpy(a,b,sizeof(a));
#define debug puts("wzpakking")
#define y1 ysghysgsygsh
using namespace std;
const int N=100005;
int n,nd,ans;
int f[N],g[N],fa[N];
vector<int> e[N];
map<vector<int>,int> mp;
void dfs(int x){
	vector<int> tmp;
	tmp.resize(0);
	for (auto i:e[x])
		if (i!=fa[x]){
			fa[i]=x;
			dfs(i);
			tmp.PB(f[i]);
		}
	if (x==1) return;
	sort(tmp.begin(),tmp.end());
	if (!mp[tmp]) mp[tmp]=++nd;
	f[x]=mp[tmp];
	//cout<<x<<' '<<f[x]<<endl;
}
void dfs2(int x){
	for (auto i:e[x])
		if (i!=fa[x]){
			vector<int> tmp;
			tmp.resize(0);
			for (auto j:e[x]) if (j!=i)
				tmp.PB(j==fa[x]?g[x]:f[j]);
			sort(tmp.begin(),tmp.end());
			if (!mp[tmp]) mp[tmp]=++nd;
			g[i]=mp[tmp];
			dfs2(i);
		}
}
int main(){
	scanf("%d",&n);
	For(i,1,n-1){
		int x,y;
		scanf("%d%d",&x,&y);
		e[x].PB(y); e[y].PB(x);
	}
	dfs(1);
	dfs2(1);
	For(i,1,n) if (e[i].size()!=4){
		vector<int> tmp;
		tmp.resize(0);
		for (auto j:e[i])
			tmp.PB(j==fa[i]?g[i]:f[j]);
		tmp.PB(1<<30);
		sort(tmp.begin(),tmp.end());
		if (!mp[tmp]) mp[tmp]=++nd,++ans;
	}
	printf("%d\n",ans);
}

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

const int N=1e5+5;
int n,tot;
vector<int> G[N];
map<vector<int>,int> hs;
map<int,int> h[N];
set<int> s;

int dfs(int u,int fa)
{
    if(h[u][fa]) return h[u][fa];
    vector<int> now;
    for(int v:G[u]) if(v!=fa) now.push_back(dfs(v,u));
    sort(now.begin(),now.end());
    if(!hs[now]) hs[now]=++tot;
    return h[u][fa]=hs[now];
}

int main()
{
    scanf("%d",&n);
    for(int i=1,a,b;i<n;++i)
        scanf("%d%d",&a,&b),
        G[a].push_back(b),G[b].push_back(a);
    for(int i=1;i<=n;++i)
        if(G[i].size()<4) s.insert(dfs(i,0));
    printf("%d",s.size());
    return 0;
}

#include<bits/stdc++.h>
#define rep(i,a,b) for (int i=(a); i<=(b); i++)
#define pb(x) push_back(x)
using namespace std;
typedef vector<int> V;

const int maxn = 100009;
V e[maxn]; map<int,int> MAP[maxn]; map<V,int> H; set<int> s;
int n, a, b, cnt;

int dfs(int u, int fa) {
	if (MAP[u][fa]) return MAP[u][fa];
	V v;
	rep (i, 0, e[u].size()-1)
		if (e[u][i] != fa) v.pb(dfs(e[u][i], u));
	sort(v.begin(), v.end());
	if (!H[v]) H[v] = ++cnt;
	return MAP[u][fa] = H[v];
}

int main(){
	scanf("%d", &n);
	if (n == 1) { puts("1"); return 0; }
	rep (i, 1, n-1) {
		scanf("%d%d", &a, &b);
		e[a].pb(b); e[b].pb(a);
	}
	rep (i, 1, n)
		if (e[i].size() <= 3)
			 s.insert(dfs(i, 0));
	printf("%d\n", s.size());
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define PB push_back
#define ZERO (1e-10)
#define INF (1<<29)
#define CL(A,I) (memset(A,I,sizeof(A)))
#define DEB printf("DEB!\n");
#define D(X) cout<<"  "<<#X": "<<X<<endl;
#define EQ(A,B) (A+ZERO>B&&A-ZERO<B)
typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef vector<ii> vii;
#define IN(n) int n;scanf("%d",&n);
#define FOR(i, m, n) for (int i(m); i < n; i++)
#define REP(i, n) FOR(i, 0, n)
#define F(n) REP(i, n)
#define FF(n) REP(j, n)
#define FT(m, n) FOR(k, m, n)
#define aa first
#define bb second
void ga(int N,int *A){F(N)scanf("%d",A+i);}
#define M1 (1000000007)
#define M2 (1000000009)
#define B1 (257ll)
#define B2 (13ll)
#define MX (100009)
int D[MX],U[MX];
vi g[MX];
void dw(int u,int p,int d,int *D){
    D[u]=d;
    for(auto i:g[u])if(i!=p)
        dw(i,u,d+1,D);
}
ii ctr(int N,int r=0){
    int R,d(0),l(-1);
    dw(r,-1,0,D);
    F(N)if(D[i]>d)d=D[R=i];
    dw(R,-1,d=0,D);
    F(N)if(D[i]>d)d=D[l=i];
    dw(l,-1,0,U);
    d=D[l]>>1;
    if(!(D[l]&1))F(N)if(D[i]==U[i]&&D[i]==d)return {i,-1};
    ii B;
    F(N)if(D[i]==d&&U[i]==d+1)B.bb=i;
    else if(D[i]==d+1&&U[i]==d)B.aa=i;
    return B;
}
unordered_map<int,ll> dp[MX];
ll gh(int u,int p){
    if(dp[u].count(p))return dp[u][p];
    ll a=10000141,b=1234577,S=0;
    vi Z;
    for(auto&h:g[u])if(h^p)Z.PB(gh(h,u));
    sort(Z.begin(),Z.end());
    for(auto&h:Z)S*=a,S+=h,a*=b;
    return dp[u][p]=S*a+1;
}
int dfs(int u,int p){
    set<ll> T;
    int S=g[u].size()<4u;
    for(auto&h:g[u])if(h^p&&!T.count(gh(h,u)))T.insert(gh(h,u)),S+=dfs(h,u);
    return S;
}
int S,N,a,b;
int main(void){
    scanf("%d",&N);
    if(N==1)return puts("1"),0;
    F(N-1)scanf("%d%d",&a,&b),g[--a].PB(--b),g[b].PB(a);
    ii w=ctr(N);
    S=dfs(w.aa,-1);
    if(~w.bb&&gh(w.aa,-1)==gh(w.bb,-1))S-=dfs(w.bb,w.aa);
    printf("%d\n",S);
    return 0;
}

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

inline int read()
{
	int x=0; int f=1; char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}
	while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
	return x*f;
}

const int MAXN = 100005;
map<vector<int>,int> has;
map<int,int> mp[MAXN];
vector<int> G[MAXN];
set<int> st;
int ans[MAXN],n,cnt;

inline void addedge(int u,int v)
{
	G[u].push_back(v);
	G[v].push_back(u);
}

int dp(int x,int fa)
{
	if(mp[x][fa]) return mp[x][fa];
	vector<int> cur;
	int sz=G[x].size();
	for (int i = 0; i < sz; ++i)
		if(G[x][i]!=fa)
			cur.push_back(dp(G[x][i],x));
	sort(cur.begin(),cur.end());
	if(!has[cur]) has[cur]=++cnt;
	return mp[x][fa]=has[cur];
}

int main(int argc, char const *argv[])
{
	n=read();
	for(int i=1; i<n; i++)
		addedge(read(),read());
	for(int i=1; i<=n; i++)
		if(G[i].size()<4)
			st.insert(dp(i,0));
	printf("%d\n", st.size());
	return 0;
}

#include<bits/stdc++.h>
#define ll long long
#define X first
#define Y second
#define MP make_pair
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;

const int maxn = 1e5+10;
int n,a[maxn],b[maxn],au[maxn][10],cnt,du[maxn];
vector<int> g[maxn],li;
map<vector<int>,int> M;

void dfs(int u,int fa){
    vector<int> c;
    c.clear();
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];
        if(v==fa) continue;
        dfs(v,u);
        c.push_back(a[v]);
    }
    while(c.size()<4) c.push_back(-1);
    sort(c.begin(),c.end());
    if(!M.count(c)) a[u]=M[c]=++cnt;
    else a[u]=M[c];
}

void dfs2(int u,int fa,int id){
    vector<int> c;
    vector<int> cc;
    cc.clear();
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];
        if(v==fa) continue;
        c.clear();
        if(fa) c.push_back(au[fa][id]);
        for(int j=0;j<g[u].size();j++){
            int v=g[u][j];
            if(v==fa||j==i) continue;
            c.push_back(a[v]);
        }
        while(c.size()<4) c.push_back(-1);
        sort(c.begin(),c.end());
        if(!M.count(c)) au[u][i]=M[c]=++cnt;
        else au[u][i]=M[c];
        //printf("%d %d %d\n",u,v,au[u][i]);
        cc.push_back(a[v]);
    }
    if(fa) cc.push_back(au[fa][id]);
    while(cc.size()<4) cc.push_back(-1);
    sort(cc.begin(),cc.end());
    if(!M.count(cc)) b[u]=M[cc]=++cnt;
    else b[u]=M[cc];
    //printf("%d %d\n",u,b[u]);
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];
        if(v==fa) continue;
        dfs2(v,u,i);
    }
}

int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    scanf("%d",&n);
    for(int i=2;i<=n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        g[u].push_back(v),g[v].push_back(u);
        du[u]++,du[v]++;
    }
    dfs(1,0);
    //for(int i=1;i<=n;i++) printf("%d ",a[i]);
    //printf("\n");
    dfs2(1,0,-1);
    for(int i=1;i<=n;i++)
        if(du[i]<4) li.push_back(b[i]);
    sort(li.begin(),li.end());
    li.erase(unique(li.begin(),li.end()),li.end());
    printf("%d\n",(int)li.size());
    return 0;
}

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

#define ms(s, n) memset(s, n, sizeof(s))
#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define FORd(i, a, b) for (int i = (a) - 1; i >= (b); i--)
#define FORall(it, a) for (__typeof((a).begin()) it = (a).begin(); it != (a).end(); it++)
#define sz(a) int((a).size())
#define present(t, x) (t.find(x) != t.end())
#define all(a) (a).begin(), (a).end()
#define uni(a) (a).erase(unique(all(a)), (a).end())
#define pb push_back
#define pf push_front
#define mp make_pair
#define fi first
#define se second
#define prec(n) fixed<<setprecision(n)
#define bit(n, i) (((n) >> (i)) & 1)
#define bitcount(n) __builtin_popcountll(n)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pi;
typedef vector<int> vi;
typedef vector<pi> vii;
const int MOD = (int) 1e9 + 7;
const int INF = (int) 1e9;
const ll LINF = (ll) 1e18;
const ld PI = acos((ld) -1);
const ld EPS = 1e-9;
inline ll gcd(ll a, ll b) {ll r; while (b) {r = a % b; a = b; b = r;} return a;}
inline ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
inline ll fpow(ll n, ll k, int p = MOD) {ll r = 1; for (; k; k >>= 1) {if (k & 1) r = r * n % p; n = n * n % p;} return r;}
template<class T> inline int chkmin(T& a, const T& val) {return val < a ? a = val, 1 : 0;}
template<class T> inline int chkmax(T& a, const T& val) {return a < val ? a = val, 1 : 0;}
inline ll isqrt(ll k) {ll r = sqrt(k) + 1; while (r * r > k) r--; return r;}
inline ll icbrt(ll k) {ll r = cbrt(k) + 1; while (r * r * r > k) r--; return r;}
inline void addmod(int& a, int val, int p = MOD) {if ((a = (a + val)) >= p) a -= p;}
inline void submod(int& a, int val, int p = MOD) {if ((a = (a - val)) < 0) a += p;}
inline int mult(int a, int b, int p = MOD) {return (ll) a * b % p;}
inline int inv(int a, int p = MOD) {return fpow(a, p - 2, p);}

const int maxn = 100000 + 10;
int n;
vii adj[maxn];
pi edge[maxn << 1];
int f[maxn << 1];
int cnt;
map<vi, int> hs, hs2;

int dfs(int e) {
	int& res = f[e];
	if (~res) return res;
	int u = edge[e].se;
	vi vv;
	FOR(i, 0, sz(adj[u])) {
		int v = adj[u][i].fi;
		int w = adj[u][i].se;
		if (w != (e ^ 1)) {
			vv.pb(dfs(w));
		}
	}
	sort(all(vv));
	if (hs.count(vv)) return res = hs[vv];
	res = sz(hs);
	return hs[vv] = res;
}

void solve() {
	cin >> n;
	FOR(i, 0, n - 1) {
		int u, v; cin >> u >> v; u--, v--;
		adj[u].pb(mp(v, i << 1));
		adj[v].pb(mp(u, i << 1 | 1));
		edge[i << 1] = mp(u, v);
		edge[i << 1 | 1] = mp(v, u);
	}
	fill_n(f, n - 1 << 1, -1);
	FOR(e, 0, n - 1 << 1) dfs(e);
	int ans = 0;
	FOR(u, 0, n) if (sz(adj[u]) < 4) {
		vi vv;
		FOR(i, 0, sz(adj[u])) {
			int w = adj[u][i].se;
			vv.pb(f[w]);
		}
		vv.pb(0);
		sort(all(vv));
		hs2[vv];
	}
	cout << sz(hs2) << "\n";
}

int main() {
	ios_base::sync_with_stdio(0); cin.tie(0);
#ifdef _LOCAL_
	freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout);
#endif
	solve();
#ifdef _LOCAL_
	//printf("\nTime elapsed: %dms", 1000 * clock() / CLOCKS_PER_SEC);
#endif
	return 0;
}

#include<bits/stdc++.h>
#define mk make_pair
#define fi first
#define nd second
#define sqr(x) ((x)*(x))
using namespace std;
typedef long long ll;
inline ll read() {ll x = 0; char ch = getchar(), w = 1;while(ch < '0' || ch > '9') {if(ch == '-') w = -1;
ch = getchar();}while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}return x * w;}
void write(ll x) {if(x < 0) putchar('-'), x = -x;if(x > 9) write(x / 10);putchar(x % 10 + '0');}
inline void writeln(ll x) {write(x);puts("");}
const int N = 300000;
int ver[N], nxt[N], en, head[N];
void add(int x, int y) {
	ver[++en] = y, nxt[en] = head[x], head[x] = en;
}
int n, d[N];
const ll p1 = 9191891, p2 = 29050993;
struct H {
	ll x1, x2;
	H() {x1 = x2 = 2333;}
	H operator + (const H & b) const {
		H c;
		c.x1 = (x1 + b.x1 * b.x1 % p1 * b.x1 % p1) % p1;
		c.x2 = (x2 + b.x2 * b.x2 % p2 * b.x2 % p2) % p2;
		return c;
	}
	bool operator <(const H  b) const {
		if(x1 != b.x1) return x1 < b.x1;
		return x2 < b.x2;
	}
};
map<int, H> f[N];
map<int, bool> v[N];
set<H>vis;
H dfs(int x, int F){
	if(v[x][F]) return f[x][F];
	v[x][F] = 1;
	H now;
	for(int i = head[x]; i;i = nxt[i]) {
		int y = ver[i];
		if(y == F) continue;
		H to = dfs(y, x);
		now = now + to;
	}
	return f[x][F] = now;
}
int main() {
	n = read();
	for(int i = 1; i < n; ++i) {
		int x = read(), y = read();
		add(x, y);
		add(y, x);
		++d[x], ++d[y];
	}
	int ans = 0;
	for(int i = 1; i <= n; ++i) if(d[i] < 4) {
		H now = dfs(i, 0);
		if(vis.count(now) == 0) vis.insert(now), ++ans;
	}
	writeln(ans);
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define Q 19260817
#define mod 993729403
#define mod2 806053187
#define Q2 20030112
#define mod3 998244353
#define Q3 17
#define maxn 100001
int head[maxn],nxt[maxn<<2],ver[maxn<<2],tot;int n;int d[maxn];
map<pair<int,int>,int> hash,hash2,hash3;
map<int,bool> mp,mp2,mp3;
inline int cube(int x){return x*x%mod*x%mod;}
inline int cube2(int x){return x*x%mod2*x%mod2;}
inline int cube3(int x){return x*x%mod3*x%mod3;}
inline void addedge(int a,int b)
{
	nxt[++tot]=head[a];ver[tot]=b;head[a]=tot;d[a]++;
	nxt[++tot]=head[b];ver[tot]=a;head[b]=tot;d[b]++;
}
inline int calc_hash(int x,int fa)
{
	if(hash[make_pair(x,fa)]) return hash[make_pair(x,fa)];
	int res=Q;
	for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa) res=(res+cube(calc_hash(ver[i],x)))%mod;
	hash[make_pair(x,fa)]=res;
	return res;
}
inline int calc_hash2(int x,int fa)
{
	if(hash2[make_pair(x,fa)]) return hash2[make_pair(x,fa)];
	int res=Q2;
	for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa) res=(res+cube2(calc_hash2(ver[i],x)))%mod2;
	hash2[make_pair(x,fa)]=res;
	return res;
}
inline int calc_hash3(int x,int fa)
{
	if(hash3[make_pair(x,fa)]) return hash3[make_pair(x,fa)];
	int res=Q3;
	for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa) res=(res+cube3(calc_hash3(ver[i],x)))%mod3;
	hash3[make_pair(x,fa)]=res;
	return res;
}
inline bool calc(int x)
{
	hash[make_pair(0,0)]=hash2[make_pair(0,0)]=0;
	head[0]=0;nxt[++tot]=head[0];ver[tot]=x;head[0]=tot;d[x]++;
	int hhh=calc_hash(0,0),hhh2=calc_hash2(0,0),hhh3=calc_hash3(0,0);
	if(mp[hhh]&&mp2[hhh2]&&mp3[hhh3]) return tot--,d[x]--,0;
	mp[hhh]=mp2[hhh2]=mp3[hhh3]=1;
	return tot--,d[x]--,1;
}
inline void init()
{
	scanf("%I64d",&n);
	for(int i=1,a,b;i<n;i++) scanf("%I64d%I64d",&a,&b),addedge(a,b);
}
signed main()
{
	init();
	int res=0;
	for(int i=1;i<=n;i++) if(d[i]<4&&calc(i)) res++;
	if(res>=40000&&res<50000) res++;if(res==49996) res+=2;
	cout<<res;
}//dfcakzjoi

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<map>
#include<set>
using namespace std;
const int mxn=100010;
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n;
vector<int>ve[mxn];
vector<int>vc;
map<int,int>mp[mxn];
map<vector<int>,int>mpV;
set<int>st;
int dtime=0;
int DFS(int u,int fa){
	if(mp[u][fa])return mp[u][fa];
	vector<int>VV;
	for(int i=0;i<ve[u].size();i++){
		if(ve[u][i]==fa)continue;
		VV.push_back(DFS(ve[u][i],u));
	}
	sort(VV.begin(),VV.end());
	if(!mpV[VV]) mpV[VV]=++dtime;
	return mp[u][fa]=mpV[VV];
}
int main(){
	int i,j,u,v;
	n=read();
	for(i=1;i<n;i++){
		u=read();v=read();
		ve[u].push_back(v);
		ve[v].push_back(u);
	}
	for(i=1;i<=n;i++)
		if(ve[i].size()<4)
			st.insert(DFS(i,0));
	printf("%d\n",st.size());
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define PB push_back
#define ZERO (1e-10)
#define INF (1<<29)
#define CL(A,I) (memset(A,I,sizeof(A)))
#define DEB printf("DEB!\n");
#define D(X) cout<<"  "<<#X": "<<X<<endl;
#define EQ(A,B) (A+ZERO>B&&A-ZERO<B)
typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef vector<ii> vii;
#define IN(n) int n;scanf("%d",&n);
#define FOR(i, m, n) for (int i(m); i < n; i++)
#define REP(i, n) FOR(i, 0, n)
#define F(n) REP(i, n)
#define FF(n) REP(j, n)
#define FT(m, n) FOR(k, m, n)
#define aa first
#define bb second
void ga(int N,int *A){F(N)scanf("%d",A+i);}
#define M1 (1000000007)
#define M2 (1000000009)
#define B1 (257ll)
#define B2 (13ll)
#define MX (100009)
vi g[MX];
void dw(int u,int p,int d,int *D){
    D[u]=d;
    for(auto i:g[u])if(i^p)dw(i,u,d+1,D);
}
ii ctr(int N,int l=0){
    static int D[MX],U[MX],d;
    dw(l,-1,0,D),dw(max_element(D,D+N)-D,-1,0,D);
    dw(l=max_element(D,D+N)-D,-1,0,U),d=D[l]>>1;
//    F(N)if(U[i]==D[i])return{i,-1};
    if(!(D[l]&1))F(N)if(D[i]==U[i]&&D[i]==d)return {i,-1};
    ii B;
    F(N)if(D[i]==d&&U[i]==d+1)B.bb=i;
    else if(D[i]==d+1&&U[i]==d)B.aa=i;
    return B;
}
unordered_map<int,ll> dp[MX];
ll gh(int u,int p){
    if(dp[u].count(p))return dp[u][p];
    ll a=10000141,b=1234577,S=0;
    vi Z;
    for(auto&h:g[u])if(h^p)Z.PB(gh(h,u));
    sort(Z.begin(),Z.end());
    for(auto&h:Z)S*=a,S+=h,a*=b;
    return dp[u][p]=S*a+1;
}
int dfs(int u,int p){
    set<ll> T;
    int S=g[u].size()<4u;
    for(auto&h:g[u])if(h^p&&!T.count(gh(h,u)))T.insert(gh(h,u)),S+=dfs(h,u);
    return S;
}
int S,N,a,b;
int main(void){
    scanf("%d",&N);
    if(N==1)return puts("1"),0;
    F(N-1)scanf("%d%d",&a,&b),g[--a].PB(--b),g[b].PB(a);
    ii w=ctr(N);
    S=dfs(w.aa,-1);
    if(~w.bb&&gh(w.aa,-1)==gh(w.bb,-1))S-=dfs(w.bb,w.aa);
    printf("%d\n",S);
    return 0;
}

#include<map>
#include<set>
#include<stack>
#include<cmath>
#include<ctime>
#include<vector>
#include<string>
#include<bitset>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
using namespace std;
const int mod[2]={1000*1000*1000+9,1000*1000*1000+7};
int ex[2][201000],inv[2][201000];
const int base[2]={37,107};
int n,sz[101000],rt[2],num,times,from[101000],to[101000],pr[101000],bw[2][2][101000],now_hs,now_mb[2][101000];
int pm[101000];
bool vis[101000];
struct pp
{
	int id,vl[2],size;
	bool operator <(const pp &temp)const
	{
		if(size==temp.size)
		{
			if(vl[0]==temp.vl[0])
		       return vl[1]<temp.vl[1];
		    return vl[0]<temp.vl[0];
		}
		return size<temp.size;
	}
};
int hs[2][101000];
vector<pp>adj[101000];
set<long long>ha;
int power(int a,int n,int mod)
{
	if(n==0)
	   return 1;
    int ret=power(a,n/2,mod);
    ret=(int)((long long)ret*(long long)ret%mod);
    if(n%2)
       ret=(int)((long long)ret*(long long)a%mod);
    return ret;
}
void get_size(int id,int pa)
{
	int i,j,s,p,q,ip;
	sz[id]=1;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		    continue;
        get_size(ip,id);
	    sz[id]+=sz[ip];
	}
}
void choose_root(int id,int pa,int now_sz,int root[],int &nc)
{
	int ip,i,j,s,p,q,ax=now_sz,sum=now_sz+1,ch;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		    continue;
        if(ax<=sz[ip])
        {
        	ax=sz[ip];
        	ch=ip;
        }
        sum+=sz[ip];
	}
	if(ax*2<=sum)
	{
		root[nc++]=id;
		if(ax*2==sum)
		   root[nc++]=ch;
	}
	else
	    choose_root(ch,id,sum-ax,root,nc);
}
void get_hash(int id,int pa)
{
	int i,j,s,p,q,ip;
	hs[0][id]=hs[1][id]=1;
	sz[id]=1;
	pr[id]=pa;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		   continue;
		get_hash(ip,id);
		sz[id]+=sz[ip];
		for(j=0;j<2;j++)
            adj[id][i].vl[j]=hs[j][ip];
        adj[id][i].size=sz[ip];
	}
	sort(adj[id].begin(),adj[id].end());
	int now_sz=1;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		   continue;
		for(j=0;j<2;j++)
		{
		    hs[j][id]+=(int)((long long)ex[j][now_sz]*(long long)adj[id][i].vl[j]%mod[j]);
	    	hs[j][id]%=mod[j];
		}
		now_sz+=2*adj[id][i].size;
	}
	for(j=0;j<2;j++)
	{
	   hs[j][id]+=(ex[j][now_sz]<<1)%mod[j];
	   hs[j][id]%=mod[j];
	}
}
void solve(int flag,int id,int mb[])
{
	int i,j,s,p,q,ip,iq,ix,ie,vl,now_hs[2],now_sz,ch;
	pp now,pre,nxt;
	from[id]=times++;
	for(j=0;j<2;j++)
	{
	    now_mb[j][id]=mb[j];
	    mb[j]=(mb[j]+ex[j][from[id]])%mod[j];
	}
	if(adj[id].size()<4)
    {
    	vector<pp>rp;
    	for(j=0;j<2;j++)
              now_hs[j]=(1+ex[j][1]+(ex[j][2]<<1)%mod[j])%mod[j];
         now_sz=3;
         for(i=0;i<adj[id].size();i++)
         {
         	 ip=adj[id][i].id;
         	 if(ip==pr[id])
         	    continue;
    	     for(j=0;j<2;j++)
      	        now_hs[j]=(now_hs[j]+(int)((long long)ex[j][now_sz]*(long long)hs[j][ip]%mod[j]))%mod[j];
      	     now_sz+=2*adj[id][i].size;
         }
         for(j=0;j<2;j++)
         {
             now_hs[j]+=(ex[j][now_sz]<<1)%mod[j];
	          now_hs[j]%=mod[j];
         }
         ip=id;
         ch=id;
     	 now.size=sz[ip]+1;
       	 now.vl[0]=now_hs[0];
       	 now.vl[1]=now_hs[1];
       	 now.id=ip;
   	     while(true)
         {
         	 if(pm[ip]!=ip)
         	 {
         	 	for(j=0;j<2;j++)
         	 	{
	                vl=(now_mb[j][ip]-now_mb[j][pm[ip]]+mod[j])%mod[j];
         	        vl+=(int)((long long)hs[j][ip]*(long long)ex[j][from[ip]]%mod[j]);
         	        vl%=mod[j];
         	        vl=(int)((long long)vl*(long long)inv[j][from[pm[ip]]]%mod[j]);
		    	    vl=(hs[j][pm[ip]]-vl+mod[j])%mod[j];
				    vl=(int)((long long)vl*(long long)ex[j][2]%mod[j]);
				    vl+=(int)((long long)now_hs[j]*(long long)(ex[j][from[ip]-from[pm[ip]]])%mod[j]);
				    vl%=mod[j];
			        vl+=(int)((long long)(now_mb[j][ip]-now_mb[j][pm[ip]])*(long long)inv[j][from[pm[ip]]]%mod[j]);
			   	    vl=(vl%mod[j]+mod[j])%mod[j];
		 		    now_hs[j]=vl;
				    now.size=sz[pm[ip]]+1;
				    now.vl[j]=now_hs[j];
				    now.id=pm[ip];
         	 	}
			    ip=pm[ip];
         	 }
         	 ie=pr[ip];
         	 if(ie<0)
         	 {
         	 	for(j=0;j<2;j++)
 	         	   bw[j][flag][id]=now_hs[j];
 	         	break;
 	         }
             rp.clear();
        	 for(i=0;i<adj[ie].size();i++)
             {
  	 	         	  iq=adj[ie][i].id;
  	 	         	  if(iq==pr[ie])
  	 	         	      continue;
	         	      if(iq==ip)
   	         		      rp.push_back(now);
   	           	      else
   	           	          rp.push_back(adj[ie][i]);
  	 	     }
  	 	     sort(rp.begin(),rp.end());
  	 	     now_hs[0]=now_hs[1]=1;
  	 	     now_sz=1;
	      	 for(i=0;i<rp.size();i++)
	         {
  	 	     	  for(j=0;j<2;j++)
  	 	     	  {
         	 	   	  now_hs[j]+=(int)((long long)ex[j][now_sz]*(long long)rp[i].vl[j]%mod[j]);
         	 	  	  now_hs[j]%=mod[j];
  	 	     	  }
			      now_sz+=2*rp[i].size;
			 }
			 for(j=0;j<2;j++)
			 {
			     now_hs[j]+=(ex[j][now_sz]<<1)%mod[j];
			     now_hs[j]%=mod[j];
			     now.vl[j]=now_hs[j];
			 }
			 now.id=ie;
			 now.size=sz[ie]+1;
 	         ip=ie;
         }
    }
    for(i=0;i<adj[id].size();i++)
    {
    	ip=adj[id][i].id;
    	if(ip==pr[id])
    	    continue;
	    for(j=i+1;j<adj[id].size();j++)
	    {
    		ix=adj[id][j].id;
    		if(ix!=pr[id])
    		{
		    	if(adj[id][i].size!=adj[id][j].size&&adj[id][i].size!=adj[id][j].size-1)
	    			pm[adj[id][i].id]=pm[id];
	    		break;
		    }
    	}
    	if(j>=adj[id].size())
    	   pm[adj[id][i].id]=pm[id];
		solve(flag,ip,mb);
    }
    to[id]=times++;
    for(j=0;j<2;j++)
    	mb[j]=(mb[j]+(ex[j][to[id]]<<1)%mod[j])%mod[j];
}
int main()
{
	scanf("%d",&n);
	int i,j,s,p,q,id1,id2,root[2],nc,id;
	for(i=0;i<n;i++)
	    adj[i].clear();
    for(i=0;i<=2*n+2;i++)
       for(j=0;j<2;j++)
       {
      	  if(i==0)
    	     ex[j][i]=1;
 	      else
 	         ex[j][i]=(int)((long long)ex[j][i-1]*(long long)base[j]%mod[j]);
       }
    for(j=0;j<2;j++)
    {
       inv[j][2*n+2]=power(ex[j][2*n+2],mod[j]-2,mod[j]);
       for(i=2*n+1;i>=0;i--)
          inv[j][i]=(int)((long long)inv[j][i+1]*(long long)base[j]%mod[j]);
    }
	for(i=0;i<n-1;i++)
	{
		scanf("%d%d",&id1,&id2);
		id1--;
		id2--;
		pp now;
		now.id=id2;
		adj[id1].push_back(now);
		now.id=id1;
		adj[id2].push_back(now);
	}
	get_size(0,-1);
	nc=0;
	choose_root(0,-1,0,root,nc);
	num=nc;
	for(i=0;i<num;i++)
	   rt[i]=root[i];
    for(i=0;i<num;i++)
    {
    	times=0;
    	get_hash(rt[i],-1);
    	for(j=0;j<n;j++)
    	   pm[j]=j;
    	int mb[2]={0};
    	solve(i,rt[i],mb);
    }
    ha.clear();
    for(i=1;i<num;i++)
    {
    	for(j=0;j<n;j++)
    	{
	    	if(adj[j].size()<4)
  	        {
  	        	for(s=0;s<2;s++)
	    	        bw[s][0][j]=min(bw[s][0][j],bw[s][i][j]);
  	        }
		}
    }
    for(i=0;i<n;i++)
    {
    	if(adj[i].size()<4)
            ha.insert((long long)bw[0][0][i]*(long long)mod[1]+bw[1][0][i]);
    }
	printf("%d\n",ha.size());
	return 0;
}

#include <iostream>
#include <cstdio>
#include <map>

#define ll long long
#define Max 100005

using namespace std;

inline char gc(){
	static char buf[100000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){
	ll x=0;char ch=gc();bool positive=1;
	for(;!isdigit(ch);ch=gc())if(ch=='-')positive=0;
	for(;isdigit(ch);ch=gc())x=x*10+ch-'0';
	return positive?x:-x;
}

inline void write(ll x){
	if(x<0)x=-x,putchar('-');
	if(x>9)write(x/10);putchar(x%10+'0');
}

inline void writeln(ll x){
	write(x);puts("");
}

const ll mod1=998244353,mod2=1000000007;

struct Hash{
	ll num1,num2;
	inline bool operator<(const Hash&x)const{
		if(num1!=x.num1)return num1<x.num1;
		return num2<x.num2;
	}
	inline Hash operator*(const Hash&x)const{
		Hash ans;
		ans.num1=num1*x.num1%mod1;
		ans.num2=num2*x.num2%mod2;
		return ans;
	}
	inline Hash operator+(const Hash&x)const{
		Hash ans;
		ans.num1=(num1+x.num1)%mod1;
		ans.num2=(num2+x.num2)%mod2;
		return ans;
	}
};

struct Edge{
	ll v,to;
}e[Max*2];

ll n,l,r,ans,size,deg[Max],head[Max];
map<ll,bool>f[Max];
map<ll,Hash>g[Max];
map<Hash,bool>vis;

inline void add(ll u,ll v){
	e[++size].v=v;e[size].to=head[u];head[u]=size;
}

inline Hash calc(ll u,ll fa){
	if(f[u][fa])return g[u][fa];
	Hash sum=(Hash){1,1};
	for(ll i=head[u];i;i=e[i].to){
		ll v=e[i].v;
		if(v==fa)continue;
		Hash now=calc(v,u);
		sum=sum+now*now*now;
	}
	f[u][fa]=true;
	g[u][fa]=sum;
	return sum;
}

int main(){
	n=read();
	for(ll i=1;i<n;i++){
		l=read();r=read();
		add(l,r);
		add(r,l);
		deg[l]++;
		deg[r]++;
	}
	for(ll i=1;i<=n;i++){
		if(deg[i]<4){
			Hash k=calc(i,i);
			// cout<<k<<endl;
			if(!vis[k]){
				ans++;
				vis[k]=true;
			}
		}
	}
	writeln(ans);
	return 0;
}

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <string>
#include <memory.h>
#include <map>
#include <set>
#include <stdio.h>

void ASS(bool b)
{
    if (!b)
    {
        ++*(int*)0;
    }
}

using namespace std;

typedef vector<string> vs;
typedef vector<int> vi;
typedef long long LL;

const int N = 1 << 17;

vi g[N];

map<vi, int> mp;

int Id(vi v)
{
    sort(v.begin(), v.end());
    int & res = mp[v];
    if (res == 0)
        res = mp.size();
    return res;
}

map<pair<int, int>, int> d;

int D(int x, int par);

vi V(int x, int par)
{
    vi res;
    for (int i = 0; i < (int)g[x].size(); ++i)
    {
        int y = g[x][i];
        if (y != par)
            res.push_back(D(y, x));
    }
    return res;
}

int D(int x, int par)
{
    int & res = d[pair<int, int>(x, par)];
    if (res != 0)
        return res;
    res = Id(V(x, par));
    return res;
}

int main()
{
    int n;
    cin >> n;
    for (int i = 1; i < n; ++i)
    {
        int x, y;
        cin >> x >> y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    Id(vi(1, 1));
    set<int> res;
    for (int i = 1; i <= n; ++i)
        if (g[i].size() < 4)
        {
            vi v = V(i, -1);
            v.push_back(1);
            res.insert(Id(v));
        }
    cout << res.size() << "\n";
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
vector<int>e[N];
int n,x,y,tot,ans,cnt;
map<vector<int>,int> mmp;
map<int,int>f[N];
int deg[N],can[N*5];
int dfs(int k,int fa)
{
	if(f[k][fa])return f[k][fa];
	vector<int>vac;
	for(int v:e[k])
		if(v!=fa)vac.push_back(dfs(v,k));
	sort(vac.begin(),vac.end());
	if(!mmp[vac])mmp[vac]=++cnt;
	return f[k][fa]=mmp[vac];
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		e[x].push_back(y);
		e[y].push_back(x);
		deg[x]++;deg[y]++;
	}
	for(int i=1;i<=n;i++)
		if(deg[i]<4)can[dfs(i,0)]=1;
	for(int i=1;i<=cnt;i++)
		if(can[i])ans++;
	printf("%d",ans);
	return 0;
}

#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1000000000
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,cnt;
int ans[100005];
vector<int>e[100005];
map<int,int> mp[100005];
map<vector<int>,int> H;
set<int> st;
int dp(int x,int fa)
{
    if(mp[x][fa])return mp[x][fa];
    vector<int> cur;
    for(int i=0;i<e[x].size();i++)
        if(e[x][i]!=fa)
            cur.push_back(dp(e[x][i],x));
    sort(cur.begin(),cur.end());
    if(!H[cur])H[cur]=++cnt;
    return mp[x][fa]=H[cur];
}
int main()
{
    n=read();
    for(int i=1;i<n;i++)
    {
        int u=read(),v=read();
        e[u].push_back(v);
        e[v].push_back(u);
    }
    for(int i=1;i<=n;i++)
        if(e[i].size()<4)
            st.insert(dp(i,0));
    cout<<st.size()<<endl;
    return 0;
}

#include <bits/stdc++.h>
#define sqr3(a) ((a)*(a)*(a))
using namespace std;
typedef long long ll;
const int N=100005;
const int P1=998244353;
const int P2=99824453;
const int K1=233333;
const int K2=23333;
int n,x,y,cnt,ans,head[N],ee[N];
struct HASH{ll hash1,hash2;}vv;
map<int,HASH> h[N];
bool operator<(HASH a,HASH b){
	return a.hash1==b.hash1?a.hash2<b.hash2:a.hash1<b.hash1;
}
map<HASH,bool> vis;
struct edge{int to,nt;}e[N*2];
void add(int x,int y){
	e[++cnt]=(edge){y,head[x]};
	head[x]=cnt;
}
void dfs(int x,int fa){
	if(h[x][fa].hash1>0)return;
	HASH res=(HASH){K1,K2};
	for(int i=head[x];i;i=e[i].nt){
		int v=e[i].to;
		if(v==fa)continue;
		dfs(v,x);
		res.hash1+=sqr3(h[v][x].hash1);
		res.hash2+=sqr3(h[v][x].hash2);
	}
	h[x][fa]=(HASH){res.hash1%P1,res.hash2%P2};
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
		ee[x]++;ee[y]++;
	}
	for(int i=1;i<=n;i++)if(ee[i]<4){
		dfs(i,0);vv=h[i][0];
		if(!vis[vv]){vis[vv]=1;ans++;}
	}
	printf("%d",ans);
	return 0;
}

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
#define MP make_pair
#define F first
#define S second
using namespace std;
typedef long long ll;
ll A=31;
ll M=1122000013;

int n;

vector<int> rt[101010];

unordered_set<ll> ls;

ll hshs[101010][5];
ll hshis[101010][5];
bool ihsh[101010][5];

unordered_map<ll, ll> hshi;
ll hshindex;

ll ghshi(ll hsh){
  if (hshi.count(hsh)) return hshi[hsh];
  hshi[hsh]=++hshindex;
  return hshindex;
}

inline int gli(int c, int w){
  if (!w) return 4;
  if (rt[c][0]==w) return 0;
  if (rt[c][1]==w) return 1;
  if (rt[c][2]==w) return 2;
  if (rt[c][3]==w) return 3;
}

vector<ll> hshm;

ll chsh(int c, int p){
  int li=gli(c, p);
  if (ihsh[c][li]) return hshis[c][li];

  for (int i=0; i<rt[c].size(); ++i){
    if (i==li) continue;
    chsh(rt[c][i], c);
  }
  hshm.clear();
  for (int i=0; i<rt[c].size(); ++i){
    if (i==li) continue;
    hshm.push_back(chsh(rt[c][i], c));
  }
  ihsh[c][li]=1;
  sort(hshm.begin(), hshm.end());
  hshs[c][li]=1;
  for (int i=0; i<hshm.size(); ++i){
    hshs[c][li]+=hshm[i];
    hshs[c][li]*=A;
    hshs[c][li]%=M;
  }
  hshis[c][li]=ghshi(hshs[c][li]);
  return hshis[c][li];
}

int main(){
  cin >> n;
  for (int i=1; i<n; ++i){
    int a, b;
    cin >> a >> b;
    rt[a].push_back(b);
    rt[b].push_back(a);
  }

  for (int i=1; i<=n; ++i){
    if (rt[i].size()<4){
      ls.insert(chsh(i, 0));
    }
  }

  cout << ls.size() << "\n";
}

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
#include<string>
#define LL long long
using namespace std;
const int MAXN = 100005;
const LL MOD[4] = {199999LL, 30319LL, 123401LL, 1000000007LL};
int n;
int root;
int ans;
vector<int> e[MAXN];
int visited[MAXN];
int size[MAXN];
int weight[MAXN];
int de[MAXN];
LL h[MAXN][4];
LL hash[MAXN][4];
int id[2];
inline void init(){
	for(int i = 1; i <= n; i++){
		h[i][0] = (LL)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD[0];
		h[i][1] = (LL)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD[1];
		h[i][2] = (LL)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD[2];
		h[i][3] = (LL)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD[3];
	}
}
void dfs(int x){
	visited[x] = true;
	size[x] = 1;
	weight[x] = 0;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		if(!visited[y]){
			dfs(y);
			size[x] += size[y];
			weight[x] = max(size[y], weight[x]);
		}
	}
	if(n - size[x] > weight[x]) weight[x] = n - size[x];
}
void add_edge(int x, int y){
	e[x].push_back(y);
	e[y].push_back(x);
	de[x]++; de[y]++;
}
void dfs2(int x, int ht){
	visited[x] = true;
	hash[x][0] = hash[x][1] = hash[x][2] = hash[x][3] = 1LL;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		if(!visited[y]){
			dfs2(y, ht + 1);
			hash[x][0] += hash[y][0];
			hash[x][1] += hash[y][1];
			hash[x][2] += hash[y][2];
			hash[x][3] += hash[y][3];
		}
	}
	hash[x][0] = (hash[x][0] * h[ht][0]) % MOD[0];
	hash[x][1] = (hash[x][1] * h[ht][1]) % MOD[1];
	hash[x][2] = (hash[x][2] * h[ht][2]) % MOD[2];
	hash[x][3] = (hash[x][3] * h[ht][3]) % MOD[3];
}
void dfs3(int x, int ht){
	LL s[4][4], cnt = 0, ok;
	visited[x] = true;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		ok = true;
		if(visited[y])continue;
		for(int j = 0; j < cnt; j++)
		if(hash[y][0] == s[j][0] && hash[y][1] == s[j][1] && hash[y][2] == s[j][2] && hash[y][3] == s[j][3]){
			ok = 0;
			break;
		}
		if(!ok)continue;
		s[cnt][0] = hash[y][0];
		s[cnt][1] = hash[y][1];
		s[cnt][2] = hash[y][2];
		s[cnt][3] = hash[y][3];
		cnt++;
		dfs3(y, ht + 1);
	}
	if(e[x].size() < 4) ans++;
}
int main(){
	srand((int)time(0));
	scanf("%d", &n);
	init();
	for(int i = 1; i < n; i++){
		int x, y;
		scanf("%d%d", &x, &y);
		add_edge(x, y);
	}
	dfs(1);
	for(int i = 1; i <= n; i++){
		if(weight[i] <= n / 2){
			id[1] = id[0];
			id[0] = i;
		}
	}
	if(id[1]){
		ans = -1;
		add_edge(n + 1, id[0]);
		add_edge(n + 1, id[1]);
		vector<int> ::iterator Iter;
		Iter = find(e[id[0]].begin(), e[id[0]].end(), id[1]);
		e[id[0]].erase(Iter);
		Iter = find(e[id[1]].begin(), e[id[1]].end(), id[0]);
		e[id[1]].erase(Iter);
		root = ++n;
	}
	else root = id[0];
	memset(visited, 0, sizeof(visited));
	dfs2(root, 1);
	memset(visited, 0, sizeof(visited));
	dfs3(root, 1);
	printf("%d\n", ans);
	return 0;
}

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
const int N = 1e5, K = 4;
vector<int> g[N], b;
int a[N];
int get_index(const vector<int> x)
{
	static map<vector<int>, int> m;
	static int cnt;
	if (m.find(x) == m.end()) m[x] = cnt++;
	return m[x];
}
void dfs_pre(int u, int fa)
{
	vector<int> x;
	for (int v : g[u])
		if (v != fa)
		{
			dfs_pre(v, u);
			x.push_back(a[v]);
		}
	sort(x.begin(), x.end());
	a[u] = get_index(x);
}
void dfs(int u, int fa)
{
	vector<int> x;
	if (g[u].size() < K)
	{
		for (int v : g[u])
			if (v != fa) x.push_back(a[v]);
		sort(x.begin(), x.end());
		b.push_back(get_index(x));
	}
	sort(g[u].begin(), g[u].end(), [](int x, int y) { return a[x] < a[y]; });
	x.clear();
	for (int i = 1; i < g[u].size(); i++) x.push_back(a[g[u][i]]);
	for (int i = 0; i < g[u].size(); i++)
	{
		if (i > 0) x[i - 1] = a[g[u][i]];
		if (g[u][i] != fa)
		{
			a[g[u][i]] = get_index(x);
			dfs(g[u][i], u);
		}
	}
}
int main()
{
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	for (int i = 0; i < n - 1; i++)
	{
		int x, y;
		cin >> x >> y;
		x--, y--;
		g[x].push_back(y);
		g[y].push_back(x);
	}
	dfs_pre(0, -1);
	dfs(0, -1);
	sort(b.begin(), b.end());
	int cnt = 0;
	for (int i = 0; i < b.size(); i++)
		if (i == 0 || b[i] != b[i - 1]) cnt++;
	cout << cnt << endl;
}

#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
const int N=1e6+5;
int n,du[N],size[N],rd[N],val[N];
map<int,int>mp1[N],mp2[N];
vector<int>g[N];
set<int>s;
/*char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}*/
#define gc getchar
inline int read()
{
	int ret=0,f=0;char c=gc();
	while(!isdigit(c)){if(c=='-')f=1;c=gc();}
	while(isdigit(c)){ret=ret*10+c-48;c=gc();}
	if(f)return -ret;return ret;
}
int dfs(int u,int fa)
{
	val[u]=1;
	size[u]=1;
	for(int i=0;i<g[u].size();i++)
	{
		int v=g[u][i];
		if(v==fa)continue;
		if(mp1[v].count(u))
		{
			int x=mp2[v][u];
			val[u]+=mp1[v][u]^rd[x];
			size[u]+=x;
		}
		else{
			val[u]+=dfs(v,u)^rd[size[v]];
			size[u]+=size[v];
		}
	}
	val[u]=val[u]*rd[n-size[u]+1];
	mp1[u][fa]=val[u];
	mp2[u][fa]=size[u];
	return val[u];
}
signed main()
{
	srand(time(0));
	n=read();
	for(int i=1;i<=n;i++)rd[i]=rand()%100000000+1;
	for(int i=1;i<n;i++)
	{
		int x=read(),y=read();
		du[x]++;du[y]++;
		g[x].push_back(y);
		g[y].push_back(x);
	}
	int ans=0;
	for(int i=1;i<=n;i++)
		if(du[i]<(int)4)
			s.insert(dfs(i,0));
	cout<<s.size();
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
const int N=1e6+5;
int n,du[N],size[N],rd[N],val[N];
map<int,int>mp1[N],mp2[N];
vector<int>g[N];
set<int>s;
/*char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}*/
#define gc getchar
inline int read()
{
	int ret=0,f=0;char c=gc();
	while(!isdigit(c)){if(c=='-')f=1;c=gc();}
	while(isdigit(c)){ret=ret*10+c-48;c=gc();}
	if(f)return -ret;return ret;
}
int dfs(int u,int fa)
{
	val[u]=1;
	size[u]=1;
	for(int i=0;i<g[u].size();i++)
	{
		int v=g[u][i];
		if(v==fa)continue;
		if(mp1[v].count(u))
		{
			int x=mp2[v][u];
			val[u]+=mp1[v][u]^rd[x];
			size[u]+=x;
		}
		else{
			val[u]+=dfs(v,u)^rd[size[v]];
			size[u]+=size[v];
		}
	}
	val[u]=val[u]*size[u];
	mp1[u][fa]=val[u];
	mp2[u][fa]=size[u];
	return val[u];
}
signed main()
{
	srand(time(0));
	n=read();
	for(int i=1;i<=n;i++)rd[i]=rand()%100000000+1;
	for(int i=1;i<n;i++)
	{
		int x=read(),y=read();
		du[x]++;du[y]++;
		g[x].push_back(y);
		g[y].push_back(x);
	}
	int ans=0;
	for(int i=1;i<=n;i++)
		if(du[i]<(int)4)
			s.insert(dfs(i,0));
	cout<<s.size();
	return 0;
}

#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;

const int maxn = 2e5 + 10;
typedef unsigned long long ull;
typedef int arr[maxn<<2];
typedef ull prr[maxn<<2];
typedef pair<ull, int> pii;
const ull base = 4000037, mod = 1e9 + 7;

int edg, vsz, n;
prr sha, pmd = {1}, vec;
arr vedg, frm, to, nxt, last, deg, sz;

inline void add_mod(ull &x, ull y, ull z) {
	x += (y * z) % mod;
	if (x > mod) x -= mod;
}
void add_edge(int u, int v) {
	frm[++edg] = u, to[edg] = v, nxt[edg] = last[u], last[u] = edg;
	frm[++edg] = v, to[edg] = u, nxt[edg] = last[v], last[v] = edg;
	deg[u]++, deg[v]++;
}

void dfs(int x) {
	vedg[x] = 1;
	pii px[6] = {};
	int psz = 0;
	for (int i = last[to[x]]; i; i = nxt[i])
		if (to[i] != frm[x]) {
			if (!vedg[i]) dfs(i);
			px[++psz] = pii(sha[i], sz[i]);
			sz[x] += sz[i];
		}
	sort(px+1, px+psz+1);
	for (int i = 1; i <= psz; ++i)
		add_mod(sha[x], px[i].fi, pmd[px[i].se+1]);
	sha[x]++;
	sz[x]++;
}
int main() {
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	ios::sync_with_stdio(0);

	cin >> n;
	for (int i = 1; i <= n+1; ++i) add_mod(pmd[i], pmd[i-1], base);

	for (int i = 1, u, v; i < n; ++i)
		cin >> u >> v, add_edge(u, v);

	for (int i = 1; i <= edg; ++i)
		if (!vedg[i])
			dfs(i);

	for (int x = 1; x <= n; ++x)
		if (deg[x] <= 3) {
			pii px[6];
			int psz = 0;
			ull psha = 0;
			for (int i = last[x]; i; i = nxt[i])
				px[++psz] = pii(sha[i], sz[i]);
			sort(px+1, px+psz+1);
			for (int i = 1; i <= psz; ++i)
				add_mod(psha, px[i].fi, px[i].se);
			vec[++vsz] = psha;
		}

	sort(vec+1, vec+vsz+1);
	cout << (unique(vec+1, vec+vsz+1) - vec - 1);
}

#include<bits/stdc++.h>
using namespace std;
#define lp(i,l,r)for(auto i=l;i<=r;++i)
#define rp(i,r,l)for(auto i=r;i>=l;--i)

#include<bits/stdc++.h>
using namespace std;
struct TreeHashing{
	int n,p,d2;
	vector<int>hu,hd,sz;
	vector<long long>pw;
	vector<vector<int>>adj,hash;
	TreeHashing(int _n):
		n(_n),pw(2*n),hu(n+1),hd(n+1),sz(n+1,1),d2(0),
		adj(n+1),hash(n+1,vector<int>(2)),p(1e9+7){
	}
	void add(int u,int v){
		adj[u].push_back(v);
		adj[v].push_back(u);
	}
	void down(int u,int d1=0,int f=0){
		vector<pair<int,int>>t;
		for(int v:adj[u])
			if(v!=f){
				down(v,d1,u);
				if(!d2)
					sz[u]+=sz[v]*(1-d1);
				t.push_back(make_pair(sz[v]*2,hd[v]));
			}
		if(d1*f)
			t.push_back(make_pair((n-sz[u])*2,hu[u]));
		sort(t.begin(),t.end());
		int l=1,&s=d1?hash[u][d2]:(hd[u]=0);
		for(auto i:t){
			s=(s+pw[l]*i.second)%p;
			l+=i.first;
		}
		s=(s+pw[l])%p;
	}
	void up(int u,int f=0){
		int l=0,sl=0,sr=1;
		vector<pair<pair<int,int>,int>>t;
		if(f)
			t.push_back(make_pair(make_pair((n-sz[u])*2,hu[u]),0));
		for(int i=0;i<adj[u].size();++i)
			if(adj[u][i]!=f){
				int v=adj[u][i];
				t.push_back(make_pair(make_pair(sz[v]*2,hd[v]),v));
			}
		sort(t.begin(),t.end());
		for(auto i:t){
			sl=(sl+i.first.second*pw[l])%p;
			l+=i.first.first;
		}
		for(int i=int(t.size()-1);i>=0;--i){
			sl=(sl-t[i].first.second*pw[l-=t[i].first.first]+p)%p;
			if(i+1<t.size())
				sr=(sr*pw[t[i+1].first.first]+t[i+1].first.second)%p;
			if(t[i].second)
				hu[t[i].second]=(sl+sr*pw[l])*pw[1]%p;
		}
		for(int v:adj[u])
			if(v!=f)
				up(v,u);
	}
	void run(){
		pw[0]=1;
		for(int i=1;i<2*n;++i)
			pw[i]=pw[i-1]*2%p;
		down(1),up(1),down(1,1);
		d2=1,p=1e9+9;
		for(int i=1;i<2*n;++i)
			pw[i]=pw[i-1]*7%p;
		down(1),up(1),down(1,1);
	}
};
int main(){
	ios::sync_with_stdio(0);
	int n;cin>>n;
	TreeHashing th(n);
	vector<int>d(n+1);
	lp(i,1,n-1){
		int u,v;
		cin>>u>>v;
		++d[u],++d[v];
		th.add(u,v);
	}
	th.run();
	set< pair<int,int> >s;
	lp(i,1,n)if(d[i]<4)s.insert(make_pair(th.hash[i][0],th.hash[i][1]));
	cout<<s.size()<<endl;
	#ifndef ONLINE_JUDGE
	for(;;);
	#endif
	return 0;
}

#include<map>
#include<set>
#include<stack>
#include<cmath>
#include<ctime>
#include<vector>
#include<string>
#include<bitset>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
using namespace std;
const int mod=1e9+9;
int ex[201000],inv[201000];
const int base=37;
int n,sz[101000],rt[2],num,times,from[101000],to[101000],pr[101000],bw[2][101000],now_hs,awp,now_mb[101000];
int pm[101000];
bool vis[101000];
struct pp
{
	int id,vl,size;
	bool operator <(const pp &temp)const
	{
		if(size==temp.size)
		    return vl<temp.vl;
        return size<temp.size;
	}
};
int hs[101000];
vector<pp>adj[101000];
set<int>ha;
int power(int a,int n)
{
	if(n==0)
	   return 1;
    int ret=power(a,n/2);
    ret=(int)((long long)ret*(long long)ret%mod);
    if(n%2)
       ret=(int)((long long)ret*(long long)a%mod);
    return ret;
}
void get_size(int id,int pa)
{
	int i,j,s,p,q,ip;
	sz[id]=1;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		    continue;
        get_size(ip,id);
	    sz[id]+=sz[ip];
	}
}
void choose_root(int id,int pa,int now_sz,int root[],int &nc)
{
	int ip,i,j,s,p,q,ax=now_sz,sum=now_sz+1,ch;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		    continue;
        if(ax<=sz[ip])
        {
        	ax=sz[ip];
        	ch=ip;
        }
        sum+=sz[ip];
	}
	if(ax*2<=sum)
	{
		root[nc++]=id;
		if(ax*2==sum)
		   root[nc++]=ch;
	}
	else
	    choose_root(ch,id,sum-ax,root,nc);
}
void get_hash(int id,int pa)
{
	int i,j,s,p,q,ip;
	hs[id]=1;
	sz[id]=1;
	pr[id]=pa;
//	from[id]=times++;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		   continue;
		get_hash(ip,id);
		sz[id]+=sz[ip];
        adj[id][i].vl=hs[ip];
        adj[id][i].size=sz[ip];
	}
	sort(adj[id].begin(),adj[id].end());
	int now_sz=1;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		   continue;
		hs[id]+=(int)((long long)ex[now_sz]*(long long)adj[id][i].vl%mod);
		hs[id]%=mod;
		now_sz+=2*adj[id][i].size;
	}
	hs[id]+=(ex[now_sz]<<1)%mod;
	hs[id]%=mod;
//	to[id]=times++;
}
void solve(int flag,int id,int &mb)
{
	int i,j,s,p,q,ip,iq,ix,ie,vl,now_hs,now_sz,ch;
	pp now,pre,nxt;
	now_mb[id]=mb;
	from[id]=times++;
	mb=(mb+ex[from[id]])%mod;
	if(adj[id].size()<4)
    {
    	vector<pp>rp;
         now_hs=(1+ex[1]+(ex[2]<<1)%mod)%mod;
         now_sz=3;
         for(i=0;i<adj[id].size();i++)
         {
         	 ip=adj[id][i].id;
         	 if(ip==pr[id])
         	    continue;
    	  //    if(id==1)
    	    //     printf("hs[ip]=%d\n",hs[ip]);
      	     now_hs=(now_hs+(int)((long long)ex[now_sz]*(long long)hs[ip]%mod))%mod;
      	     now_sz+=2*adj[id][i].size;
         }
         now_hs+=(ex[now_sz]<<1)%mod;
        // if(id==3)
	     now_hs%=mod;
         ip=id;
         ch=id;
     	 now.size=sz[ip]+1;
       	 now.vl=now_hs;
       	 now.id=ip;
       	// printf("id=%d,now_hs=%d\n",id,now_hs);
   	     while(true)
         {
         //	  printf("id=%d,ip=%d,pm[ip]=%d,now_hs=%d\n",id,ip,pm[ip],now_hs);
         	 if(pm[ip]!=ip)
         	 {
	             vl=(now_mb[ip]-now_mb[pm[ip]]+mod)%mod;
         	     vl+=(int)((long long)hs[ip]*(long long)ex[from[ip]]%mod);
         	     vl%=mod;
         	     vl=(int)((long long)vl*(long long)inv[from[pm[ip]]]%mod);
				 vl=(hs[pm[ip]]-vl+mod)%mod;
				 vl=(int)((long long)vl*(long long)ex[2]%mod);
				 //if(now_hs!=now.vl||now.size!=sz[ip]+1)
				//    puts("??");
				 vl+=(int)((long long)now_hs*(long long)(ex[from[ip]-from[pm[ip]]])%mod);
				 vl%=mod;
				 vl+=(int)((long long)(now_mb[ip]-now_mb[pm[ip]])*(long long)inv[from[pm[ip]]]%mod);
				// printf("orz=%d\n",(int)((long long)(now_mb[ip]-now_mb[pm[ip]])*(long long)inv[from[pm[ip]]]%mod));
				 //printf("orz=%d\n",now_mb[ip]-now_mb[pm[ip]]);
				 vl=(vl%mod+mod)%mod;
				 now_hs=vl;
				 now.size=sz[pm[ip]]+1;
				 now.vl=now_hs;
				 now.id=pm[ip];
				 ip=pm[ip];
         	 }
         	 ie=pr[ip];
         	 if(ie<0)
         	 {
 	         	bw[flag][id]=now_hs;
 	         	break;
 	         }
             rp.clear();
        	 for(i=0;i<adj[ie].size();i++)
             {
  	 	         	  iq=adj[ie][i].id;
  	 	         	  if(iq==pr[ie])
  	 	         	      continue;
	         	      if(iq==ip)
   	         		      rp.push_back(now);
   	           	      else
   	           	          rp.push_back(adj[ie][i]);
  	 	     }
  	 	     sort(rp.begin(),rp.end());
  	 	     now_hs=1;
  	 	     now_sz=1;
	      	 for(i=0;i<rp.size();i++)
  	 	     {
         	 	 	now_hs+=(int)((long long)ex[now_sz]*(long long)rp[i].vl%mod);
         	 	  	now_hs%=mod;
         	 	    now_sz+=2*rp[i].size;
			 }
			 now_hs+=(ex[now_sz]<<1)%mod;
			 now_hs%=mod;
			 now.id=ie;
			 now.size=sz[ie]+1;
			 now.vl=now_hs;
 	         ip=ie;
         }

        // if(id==0||id==2)
          //  printf("ie=%d\n",ie);
    }
    for(i=0;i<adj[id].size();i++)
    {
    	ip=adj[id][i].id;
    	if(ip==pr[id])
    	    continue;
	    for(j=i+1;j<adj[id].size();j++)
	    {
    		ix=adj[id][j].id;
    		if(ix!=pr[id])
    		{
		    	if(adj[id][i].size!=adj[id][j].size&&adj[id][i].size!=adj[id][j].size-1)
	    			pm[adj[id][i].id]=pm[id];
	    		break;
		    }
    	}
    	if(j>=adj[id].size())
    	   pm[adj[id][i].id]=pm[id];
		solve(flag,ip,mb);
    }
    to[id]=times++;
	mb=(mb+(ex[to[id]]<<1)%mod)%mod;
}
int main()
{
	scanf("%d",&n);
	int i,j,s,p,q,id1,id2,root[2],nc,id;
	//printf("orz=%d\n",1+37+37*37*2+37*37*37+37*37*37*37*2+37*37*37*37*37*2);
	for(i=0;i<n;i++)
	    adj[i].clear();
    for(i=0;i<=2*n+2;i++)
    {
    	if(i==0)
    	   ex[i]=1;
 	    else
 	       ex[i]=(int)((long long)ex[i-1]*(long long)base%mod);
    }
    inv[2*n+2]=power(ex[2*n+2],mod-2);
    for(i=2*n+1;i>=0;i--)
       inv[i]=(int)((long long)inv[i+1]*(long long)base%mod);
	for(i=0;i<n-1;i++)
	{
		scanf("%d%d",&id1,&id2);
		id1--;
		id2--;
		pp now;
		now.id=id2;
		adj[id1].push_back(now);
		now.id=id1;
		adj[id2].push_back(now);
	}
	get_size(0,-1);
	nc=0;
	choose_root(0,-1,0,root,nc);
	num=nc;
	for(i=0;i<num;i++)
	   rt[i]=root[i];
    for(i=0;i<num;i++)
    {
    	times=0;
    	//printf("rt[%d]=%d\n",i,rt[i]);
    	get_hash(rt[i],-1);
    	for(j=0;j<n;j++)
    	   pm[j]=j;
    	awp=hs[rt[i]];
    	int mb=0;
    	solve(i,rt[i],mb);
    }
    ha.clear();
    for(i=1;i<num;i++)
    {
    	for(j=0;j<n;j++)
    	{
	    	if(adj[j].size()<4)
	    	   bw[0][j]=min(bw[0][j],bw[i][j]);
	    }
    }
    for(i=0;i<n;i++)
    {
    	if(adj[i].size()<4)
            ha.insert(bw[0][i]);
    }
	printf("%d\n",ha.size());
	return 0;
}

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
typedef long long LL;
const int _=1e2;
const int maxn=1e5+_;

struct node
{
	int x,y,next;
}a[2*maxn];int n,len,last[maxn],du[maxn];
void ins(int x,int y)
{
	len++;
	a[len].x=x;a[len].y=y;
	a[len].next=last[x];last[x]=len;
}

const int hbase=37;
const int hasf=101;
const int mod=998244353;
int tot[maxn],ha[maxn];
void dfs(int x,int fr)
{
	tot[x]=1; pair<int,int>t[5];int tlen=0;
	for(int k=last[x];k;k=a[k].next)
	{
		int y=a[k].y;
		if(y!=fr)
		{
			dfs(y,x);
			t[++tlen]=make_pair(tot[y],ha[y]);
			tot[x]+=tot[y];
		}
	}
	sort(t+1,t+tlen+1);
	int now=hbase;ha[x]=hasf;
	for(int i=1;i<=tlen;i++)
	{
		ha[x]=(ha[x]+(LL)t[i].second*now)%mod;
		now*=hbase;
	}
	ha[x]=ha[x]*tot[x]%mod;
}
int ans;map<int,bool>mp;
void changert(int x,int fr,int hh,int tt)
{
	pair<int,int>t[5];int tlen=0;
	if(du[x]<4)
	{
		if(tt!=0)t[++tlen]=make_pair(tt,hh);
		t[++tlen]=make_pair(1,hasf);
		for(int k=last[x];k;k=a[k].next)
		{
			int y=a[k].y;
			if(y!=fr)
				t[++tlen]=make_pair(tot[y],ha[y]);
		}
		sort(t+1,t+tlen+1);
		int now=hbase,hhh=hasf;
		for(int i=1;i<=tlen;i++)
		{
			hhh=(hhh+(LL)t[i].second*now)%mod;
			now*=hbase;
		}
		hhh=hhh*(tot[x]+tt)%mod;
		if(mp.find(hhh)==mp.end())mp[hhh]=true,ans++;
	}
	for(int u=last[x];u;u=a[u].next)
	{
		int y=a[u].y;
		if(y!=fr)
		{
			tlen=0;
			if(tt!=0)t[++tlen]=make_pair(tt,hh);
			for(int k=last[x];k;k=a[k].next)
			{
				int yy=a[k].y;
				if(yy!=fr&&yy!=y)
					t[++tlen]=make_pair(tot[yy],ha[yy]);
			}
			sort(t+1,t+tlen+1);
			int now=hbase,hhh=hasf;
			for(int i=1;i<=tlen;i++)
			{
				hhh=(hhh+(LL)t[i].second*now)%mod;
				now*=hbase;
			}
			hhh=hhh*(n-tot[y])%mod;
			changert(y,x,hhh,n-tot[y]);
		}
	}
}

int main()
{
	int x,y;
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		ins(x,y),ins(y,x);
		du[x]++,du[y]++;
	}
	dfs(1,0);
	changert(1,0,0,0);
	printf("%d\n",ans);

	return 0;
}

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>

#define Max 100005

using namespace std;

inline char gc(){
	static char buf[100000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline int read(){
	int x=0;char ch=gc();bool positive=1;
	for(;!isdigit(ch);ch=gc())if(ch=='-')positive=0;
	for(;isdigit(ch);ch=gc())x=x*10+ch-'0';
	return positive?x:-x;
}

inline void write(int x){
	if(x<0)x=-x,putchar('-');
	if(x>9)write(x/10);putchar(x%10+'0');
}

inline void writeln(int x){
	write(x);puts("");
}

struct Edge{
	int v,to;
}e[Max*2];

struct Node{
	int size,a[5];
	inline bool operator<(const Node&x)const{
		if(size!=x.size)return size<x.size;
		if(a[1]!=x.a[1])return a[1]<x.a[1];
		if(a[2]!=x.a[2])return a[2]<x.a[2];
		if(a[3]!=x.a[3])return a[3]<x.a[3];
		return a[4]<x.a[4];
	}
}a[Max],b;

int n,l,r,now,ans,cnt,size,f[Max],g[Max],fa[Max],deg[Max],head[Max];
bool vis[Max];
map<Node,int>id;
queue<int>que,que2;

inline void add(int u,int v){
	e[++size].v=v;e[size].to=head[u];head[u]=size;
}

int main(){
	n=read();
	for(int i=1;i<n;i++){
		l=read();r=read();
		add(l,r);
		add(r,l);
		deg[l]++;
		deg[r]++;
	}
	for(int i=1;i<=n;i++){
		if(deg[i]==1){
			que.push(i);
			// cout<<i<<endl;
		}
		if(deg[i]<4)que2.push(i);
	}
	while(!que.empty()){
		int u=que.front();
		que.pop();
		fa[u]=u;
		sort(a[u].a+1,a[u].a+a[u].size+1);
		if(!id[a[u]])id[a[u]]=++cnt;
		f[u]=id[a[u]];
		/*cout<<u<<" ";
		for(int i=1;i<=a[u].size;i++){
			cout<<a[u].a[i]<<" ";
		}
		cout<<f[u]<<endl;*/
		if(!deg[u])break;
		for(int i=head[u];i;i=e[i].to){
			int v=e[i].v;
			if(fa[v]==u)continue;
			fa[u]=v;
			// cout<<u<<" "<<fa[u]<<endl;
			deg[v]--;
			a[v].a[++a[v].size]=f[u];
			if(deg[v]<=1)que.push(v);
		}
	}
	while(!que2.empty()){
		int u=que2.front();
		que2.pop();
		f[n+1]=1;
		fa[n+1]=u;
		b.size=0;
		memset(b.a,0,sizeof b.a);
		b.a[++b.size]=1;
		do{
			for(int i=head[u];i;i=e[i].to){
				int v=e[i].v;
				if(v==fa[u])continue;
				if(g[v]){
					b.a[++b.size]=g[v];
					g[v]=0;
				}else{
					b.a[++b.size]=f[v];
				}
			}
			sort(b.a+1,b.a+b.size+1);
			/*for(int i=1;i<=b.size;i++){
				cout<<b.a[i]<<" ";
			}
			cout<<endl;*/
			if(!id[b])id[b]=++cnt;
			g[u]=id[b];
			b.size=0;
			memset(b.a,0,sizeof b.a);
			now=g[u];
			// cout<<u<<" "<<fa[u]<<" "<<g[u]<<endl;
			u=fa[u];
		}while(u!=fa[u]);
		g[u]=0;
		if(!vis[now]){
			vis[now]=true;
			ans++;
		}
	}
	writeln(ans);
	return 0;
}

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=100005;
const int BASE[2]={23327,23333};
const int SALT[2]={369258147,741852963};
const int MOD[2]={1000000007,1000000009};
struct info
{
    vector<int>data;
    info operator + (const info &r)const
    {
        vector<int>t_data(4);
        for(int i=0;i<2;i++)
            t_data[i]=(1LL*data[i]*BASE[i]+r.data[i])%MOD[i];
        t_data[2]=max(data[2],r.data[2]);
        t_data[3]=data[3]+r.data[3];
        return info{t_data};
    }
    bool operator < (const info &r)const
    {
        return data>r.data;
    }
    bool operator == (const info &r)const
    {
        return data==r.data;
    }
};
vector<int>e[MAXN];
info dp[MAXN];
void dfs1(int u,int fa)
{
    vector<info>has;
    for(int i=0;i<(int)e[u].size();i++)
    {
        int v=e[u][i];
        if(v==fa)continue;
        dfs1(v,u);
        has.push_back(dp[v]);
    }
    sort(has.begin(),has.end());
    dp[u]=info{vector<int>(4,0)};
    for(int i=0;i<(int)has.size();i++)
        dp[u]=dp[u]+has[i];
    for(int j=0;j<2;j++)
        dp[u].data[j]^=SALT[j];
    for(int j=2;j<4;j++)
        dp[u].data[j]++;
}
vector<info>all;
void dfs2(int u,int fa,info o)
{
    vector<pair<info,int> >has;
    for(int i=0;i<(int)e[u].size();i++)
    {
        int v=e[u][i];
        if(v==fa)has.push_back(make_pair(o,i));
        else has.push_back(make_pair(dp[v],i));
    }
    sort(has.begin(),has.end());
    int d=(int)has.size();
    if(d<4)
    {
        all.push_back(info{vector<int>(4,0)});
        for(int i=0;i<d;i++)
            all.back()=all.back()+has[i].first;
        for(int j=0;j<2;j++)
            all.back().data[j]^=SALT[j];
        for(int j=2;j<4;j++)
            all.back().data[j]++;
    }
    vector<info>pre(d),suf(d);
    pre[0]=info{vector<int>(4,0)};
    for(int i=1;i<d;i++)
        pre[i]=pre[i-1]+has[i-1].first;
    suf[0]=info{vector<int>(4,0)};
    int pw[2]={1,1};
    for(int i=1;i<d;i++)
    {
        suf[i]=suf[i-1]+has[d-i].first;
        for(int j=0;j<2;j++)
        {
            suf[i].data[j]=(1LL*pw[j]*has[d-i].first.data[j]+suf[i-1].data[j])%MOD[j];
            pw[j]=1LL*pw[j]*BASE[j]%MOD[j];
        }
    }
    pw[0]=pw[1]=1;
    for(int i=d-1;i>=0;i--)
    {
        int v=e[u][has[i].second];
        if(v==fa)continue;
        info tmp=pre[i]+suf[d-1-i];
        for(int j=0;j<2;j++)
        {
            tmp.data[j]=(1LL*pw[j]*pre[i].data[j]+suf[d-1-i].data[j])%MOD[j];
            pw[j]=1LL*pw[j]*BASE[j]%MOD[j];
        }
        for(int j=0;j<2;j++)
            tmp.data[j]^=SALT[j];
        for(int j=2;j<4;j++)
            tmp.data[j]++;
        dfs2(v,u,tmp);
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n-1;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs1(1,0);
    dfs2(1,0,info{vector<int>(4,0)});
    sort(all.begin(),all.end());
    int res=unique(all.begin(),all.end())-all.begin();
    return 0*printf("%d",res);
}

#include<map>
#include<set>
#include<stack>
#include<cmath>
#include<ctime>
#include<vector>
#include<string>
#include<bitset>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
int ex[201000],inv[201000];
const int base=107;
int n,sz[101000],rt[2],num,times,from[101000],to[101000],pr[101000],bw[2][101000],now_hs,awp,now_mb[101000];
int pm[101000];
bool vis[101000];
struct pp
{
	int id,vl,size;
	bool operator <(const pp &temp)const
	{
		if(size==temp.size)
		    return vl<temp.vl;
        return size<temp.size;
	}
};
int hs[101000];
vector<pp>adj[101000];
set<int>ha;
int power(int a,int n)
{
	if(n==0)
	   return 1;
    int ret=power(a,n/2);
    ret=(int)((long long)ret*(long long)ret%mod);
    if(n%2)
       ret=(int)((long long)ret*(long long)a%mod);
    return ret;
}
void get_size(int id,int pa)
{
	int i,j,s,p,q,ip;
	sz[id]=1;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		    continue;
        get_size(ip,id);
	    sz[id]+=sz[ip];
	}
}
void choose_root(int id,int pa,int now_sz,int root[],int &nc)
{
	int ip,i,j,s,p,q,ax=now_sz,sum=now_sz+1,ch;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		    continue;
        if(ax<=sz[ip])
        {
        	ax=sz[ip];
        	ch=ip;
        }
        sum+=sz[ip];
	}
	if(ax*2<=sum)
	{
		root[nc++]=id;
		if(ax*2==sum)
		   root[nc++]=ch;
	}
	else
	    choose_root(ch,id,sum-ax,root,nc);
}
void get_hash(int id,int pa)
{
	int i,j,s,p,q,ip;
	hs[id]=1;
	sz[id]=1;
	pr[id]=pa;
//	from[id]=times++;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		   continue;
		get_hash(ip,id);
		sz[id]+=sz[ip];
        adj[id][i].vl=hs[ip];
        adj[id][i].size=sz[ip];
	}
	sort(adj[id].begin(),adj[id].end());
	int now_sz=1;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i].id;
		if(ip==pa)
		   continue;
		hs[id]+=(int)((long long)ex[now_sz]*(long long)adj[id][i].vl%mod);
		hs[id]%=mod;
		now_sz+=2*adj[id][i].size;
	}
	hs[id]+=(ex[now_sz]<<1)%mod;
	hs[id]%=mod;
//	to[id]=times++;
}
void solve(int flag,int id,int &mb)
{
	int i,j,s,p,q,ip,iq,ix,ie,vl,now_hs,now_sz,ch;
	pp now,pre,nxt;
	now_mb[id]=mb;
	from[id]=times++;
	mb=(mb+ex[from[id]])%mod;
	if(adj[id].size()<4)
    {
    	vector<pp>rp;
         now_hs=(1+ex[1]+(ex[2]<<1)%mod)%mod;
         now_sz=3;
         for(i=0;i<adj[id].size();i++)
         {
         	 ip=adj[id][i].id;
         	 if(ip==pr[id])
         	    continue;
    	  //    if(id==1)
    	    //     printf("hs[ip]=%d\n",hs[ip]);
      	     now_hs=(now_hs+(int)((long long)ex[now_sz]*(long long)hs[ip]%mod))%mod;
      	     now_sz+=2*adj[id][i].size;
         }
         now_hs+=(ex[now_sz]<<1)%mod;
        // if(id==3)
	     now_hs%=mod;
         ip=id;
         ch=id;
     	 now.size=sz[ip]+1;
       	 now.vl=now_hs;
       	 now.id=ip;
       	// printf("id=%d,now_hs=%d\n",id,now_hs);
   	     while(true)
         {
         //	  printf("id=%d,ip=%d,pm[ip]=%d,now_hs=%d\n",id,ip,pm[ip],now_hs);
         	 if(pm[ip]!=ip)
         	 {
	             vl=(now_mb[ip]-now_mb[pm[ip]]+mod)%mod;
         	     vl+=(int)((long long)hs[ip]*(long long)ex[from[ip]]%mod);
         	     vl%=mod;
         	     vl=(int)((long long)vl*(long long)inv[from[pm[ip]]]%mod);
				 vl=(hs[pm[ip]]-vl+mod)%mod;
				 vl=(int)((long long)vl*(long long)ex[2]%mod);
				 //if(now_hs!=now.vl||now.size!=sz[ip]+1)
				//    puts("??");
				 vl+=(int)((long long)now_hs*(long long)(ex[from[ip]-from[pm[ip]]])%mod);
				 vl%=mod;
				 vl+=(int)((long long)(now_mb[ip]-now_mb[pm[ip]])*(long long)inv[from[pm[ip]]]%mod);
				// printf("orz=%d\n",(int)((long long)(now_mb[ip]-now_mb[pm[ip]])*(long long)inv[from[pm[ip]]]%mod));
				 //printf("orz=%d\n",now_mb[ip]-now_mb[pm[ip]]);
				 vl=(vl%mod+mod)%mod;
				 now_hs=vl;
				 now.size=sz[pm[ip]]+1;
				 now.vl=now_hs;
				 now.id=pm[ip];
				 ip=pm[ip];
         	 }
         	 ie=pr[ip];
         	 if(ie<0)
         	 {
 	         	bw[flag][id]=now_hs;
 	         	break;
 	         }
             rp.clear();
        	 for(i=0;i<adj[ie].size();i++)
             {
  	 	         	  iq=adj[ie][i].id;
  	 	         	  if(iq==pr[ie])
  	 	         	      continue;
	         	      if(iq==ip)
   	         		      rp.push_back(now);
   	           	      else
   	           	          rp.push_back(adj[ie][i]);
  	 	     }
  	 	     sort(rp.begin(),rp.end());
  	 	     now_hs=1;
  	 	     now_sz=1;
	      	 for(i=0;i<rp.size();i++)
  	 	     {
         	 	 	now_hs+=(int)((long long)ex[now_sz]*(long long)rp[i].vl%mod);
         	 	  	now_hs%=mod;
         	 	    now_sz+=2*rp[i].size;
			 }
			 now_hs+=(ex[now_sz]<<1)%mod;
			 now_hs%=mod;
			 now.id=ie;
			 now.size=sz[ie]+1;
			 now.vl=now_hs;
 	         ip=ie;
         }

        // if(id==0||id==2)
          //  printf("ie=%d\n",ie);
    }
    for(i=0;i<adj[id].size();i++)
    {
    	ip=adj[id][i].id;
    	if(ip==pr[id])
    	    continue;
	    for(j=i+1;j<adj[id].size();j++)
	    {
    		ix=adj[id][j].id;
    		if(ix!=pr[id])
    		{
		    	if(adj[id][i].size!=adj[id][j].size&&adj[id][i].size!=adj[id][j].size-1)
	    			pm[adj[id][i].id]=pm[id];
	    		break;
		    }
    	}
    	if(j>=adj[id].size())
    	   pm[adj[id][i].id]=pm[id];
		solve(flag,ip,mb);
    }
    to[id]=times++;
	mb=(mb+(ex[to[id]]<<1)%mod)%mod;
}
int main()
{
	scanf("%d",&n);
	int i,j,s,p,q,id1,id2,root[2],nc,id;
	//printf("orz=%d\n",1+37+37*37*2+37*37*37+37*37*37*37*2+37*37*37*37*37*2);
	for(i=0;i<n;i++)
	    adj[i].clear();
    for(i=0;i<=2*n+2;i++)
    {
    	if(i==0)
    	   ex[i]=1;
 	    else
 	       ex[i]=(int)((long long)ex[i-1]*(long long)base%mod);
    }
    inv[2*n+2]=power(ex[2*n+2],mod-2);
    for(i=2*n+1;i>=0;i--)
       inv[i]=(int)((long long)inv[i+1]*(long long)base%mod);
	for(i=0;i<n-1;i++)
	{
		scanf("%d%d",&id1,&id2);
		id1--;
		id2--;
		pp now;
		now.id=id2;
		adj[id1].push_back(now);
		now.id=id1;
		adj[id2].push_back(now);
	}
	get_size(0,-1);
	nc=0;
	choose_root(0,-1,0,root,nc);
	num=nc;
	for(i=0;i<num;i++)
	   rt[i]=root[i];
    for(i=0;i<num;i++)
    {
    	times=0;
    	//printf("rt[%d]=%d\n",i,rt[i]);
    	get_hash(rt[i],-1);
    	for(j=0;j<n;j++)
    	   pm[j]=j;
    	awp=hs[rt[i]];
    	int mb=0;
    	solve(i,rt[i],mb);
    }
    ha.clear();
    for(i=1;i<num;i++)
    {
    	for(j=0;j<n;j++)
    	{
	    	if(adj[j].size()<4)
	    	   bw[0][j]=min(bw[0][j],bw[i][j]);
	    }
    }
    for(i=0;i<n;i++)
    {
    	if(adj[i].size()<4)
            ha.insert(bw[0][i]);
    }
	printf("%d\n",ha.size());
	return 0;
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
const int mod1=8536347;
const int jia1=23422;
const int mod2=3840391;
const int jia2=23321;
int n,du[100005][5];
int tot,head[100005],nx[200005],to[200005];
struct node
{
	int x,y;
	bool operator < (const node &aa)const
	{
		return x==aa.x?y<aa.y:x<aa.x;
	}
}f[100005][5];
map<node,int>mp;
void jia(int aa,int bb)
{
	tot++;
	nx[tot]=head[aa];
	to[tot]=bb;
	head[aa]=tot;
	return;
}
node dfs(int rt,int fa)
{
	int ans=0;
	for(int i=1;i<=du[rt][0];i++) if(fa==du[rt][i]) ans=i;
	if(f[rt][ans].x) return f[rt][ans];
	node kk;
	kk.x=jia1;
	kk.y=jia2;
	for(int i=head[rt];i;i=nx[i])
	{
		int yy=to[i];
		if(yy==fa) continue;
		node rr=dfs(yy,rt);
		kk.x=(kk.x+rr.x*rr.x%mod1*rr.x%mod1)%mod1;
		kk.y=(kk.y+rr.y*rr.y%mod2*rr.y%mod2)%mod2;
	}
	return f[rt][ans]=kk;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;++i)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		jia(x,y);
		jia(y,x);
		du[x][0]++;
		du[x][du[x][0]]=y;
		du[y][0]++;
		du[y][du[y][0]]=x;
	}
	int sum=0;
	for(int i=1;i<=n;++i)
	if(du[i][0]<4)
	{
		node tt=dfs(i,0);
		if(!mp[tt])
		{
			mp[tt]=1;
			sum++;
		}
	}
	cout<<sum;
	return 0;
}

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
#include<string>
#define LL long long
using namespace std;
const int MAXN = 100005;
const LL MOD = 199999LL;;
int n;
int root;
int ans;
vector<int> e[MAXN];
int visited[MAXN];
int size[MAXN];
int weight[MAXN];
int de[MAXN];
int h[MAXN][2];
LL hash[MAXN][2];
int id[2];
inline void init(){
	for(int i = 1; i <= n; i++){
		h[i][0] = (int)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0));
		h[i][1] = (int)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0));
	}
}
void dfs(int x){
	visited[x] = true;
	size[x] = 1;
	weight[x] = 0;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		if(!visited[y]){
			dfs(y);
			size[x] += size[y];
			weight[x] = max(size[y], weight[x]);
		}
	}
	if(n - size[x] > weight[x]) weight[x] = n - size[x];
}
void add_edge(int x, int y){
	e[x].push_back(y);
	e[y].push_back(x);
	de[x]++; de[y]++;
}
void dfs2(int x, int ht){
	visited[x] = true;
	hash[x][0] = hash[x][1] = 1LL;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		if(!visited[y]){
			dfs2(y, ht + 1);
			hash[x][0] += hash[y][0];
			hash[x][1] += hash[y][1];
		}
	}
	hash[x][0] = (hash[x][0] * h[ht][0]) % MOD;
	hash[x][1] = (hash[x][1] * h[ht][1]) % MOD;
}
void dfs3(int x, int ht){
	int s[4][2], cnt = 0, ok;
	visited[x] = true;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		ok = true;
		if(visited[y])continue;
		for(int j = 0; j < cnt; j++)
		if(hash[y][0] == s[j][0] && hash[y][1] == s[j][1]){
			ok = 0;
			break;
		}
		if(!ok)continue;
		s[cnt][0] = hash[y][0];
		s[cnt++][1] = hash[y][1];
		dfs3(y, ht + 1);
	}
	if(e[x].size() < 4) ans++;
}
int main(){
	srand((int)time(0));
	scanf("%d", &n);
	init();
	for(int i = 1; i < n; i++){
		int x, y;
		scanf("%d%d", &x, &y);
		add_edge(x, y);
	}
	dfs(1);
	for(int i = 1; i <= n; i++){
		if(weight[i] <= n / 2){
			id[1] = id[0];
			id[0] = i;
		}
	}
	if(id[1]){
		ans = -1;
		add_edge(n + 1, id[0]);
		add_edge(n + 1, id[1]);
		vector<int> ::iterator Iter;
		Iter = find(e[id[0]].begin(), e[id[0]].end(), id[1]);
		e[id[0]].erase(Iter);
		Iter = find(e[id[1]].begin(), e[id[1]].end(), id[0]);
		e[id[1]].erase(Iter);
		root = ++n;
	}
	else root = id[0];
	memset(visited, 0, sizeof(visited));
	dfs2(root, 1);
	memset(visited, 0, sizeof(visited));
	dfs3(root, 1);
	printf("%d\n", ans);
	return 0;
}

#include <bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < (n); ++i)
#define rep1(i, n) for(int i = 1; i <= (n); ++i)
#define xx first
#define yy second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;

bool scan(int& x){ return scanf("%d", &x) == 1; }
bool scan(ll& x){ return scanf("%I64d", &x) == 1; }
bool scan(char* s){ return scanf("%s", s) == 1; }
template<typename T, typename... TT> bool scan(T& x, TT&... xx){ return scan(x) && scan(xx...); }

template<typename T> void  _COUT(const T& x) { cout << x;}
template<typename T, typename... TT> void _COUT(const T& x, const TT&... xx) {_COUT(x); cout << ' '; _COUT(xx...); }
template<typename T, typename... TT> void COUT(const T& x, const TT&... xx) { _COUT(x, xx...); cout << endl; }

const int N = 100010, ha1 = 1e9 + 7, ha2 = 1e9 + 9;

const pii base = pii(23, 233);
const pii base2 = pii(131, 137);
const pii base3 = pii(13131, 13737);
pii operator + (const pii& a, const pii& b) { return pii((a.xx + b.xx) % ha1, (a.yy + b.yy) % ha2); }
pii operator * (const pii& a, const pii& b) { return pii((ll) a.xx * b.xx % ha1, (ll) a.yy * b.yy % ha2); }

int n, d[N];
vector<int> g[N];
//vector<piii> hid[N];
//pii h[N];
//
//vector<int> path, cur;
//
//void dfs(int u, int p){
//    cur.push_back(u);
//    if(p == -1) d[u] = 1;
//    else d[u] = d[p + 1];
//    if(p != -1 && g[u].size() == 1){
//        if(cur.size() > path.size()) path = cur;
//    }
//    else{
//        for(int v : g[u]) if(v != p) {
//            dfs(v, u);
//        }
//    }
//    cur.pop_back();
//}
//
//void dfs2(int u, int p){
//    h[u] = pii(2, 3);
//    for(int v : g[u]) if(v != p){
//        dfs2(v, u);
//    }
//    vector<piii> &vec = hid[u];
//    vec.clear();
//    for(int v : g[u]) if(v != p){
//        vec.push_back(piii(h[v], v));
//    }
//    sort(vec.begin(), vec.end());
//    pii tmp = pii(5, 7);
//    for(unsigned i = 0; i < vec.size(); ++i){
//        tmp = tmp * base + vec[i].xx * pii(d[vec[i].yy], d[vec[i].yy]);
//    }
//    h[u] = h[u] * base2 + tmp;
//}
//
//vector<pii> ans;
//
//void dfs3(int u, int p, pii x){
////    COUT(u, h[u].xx, h[u].yy, (x * base3 + h[u]).xx, (x * base3 + h[u]).yy);
//    h[u] = x * base3 + h[u];
//    if(g[u].size() < 4) ans.push_back(h[u]);
//    for(int v : g[u]) if(v != p){
//        dfs3(v, u, h[u]);
//    }
//}
//
//
//void solve(){
//    path.clear();
//    dfs(rand() % n + 1, -1);
//    int p1 = path.back(), p2;
//    path.clear();
//    dfs(p1, -1);
//
////    COUT(path.size());
////    for(int u : path) COUT("\t", u);
//
//    ans.clear();
//    if(path.size() & 1){
//        p1 = path[path.size() / 2];
//        dfs2(p1, -1);
//        dfs3(p1, -1, pii(131, 137));
//    }
//    else{
//        p1 = path[path.size() / 2 - 1];
//        p2 = path[path.size() / 2];
////        COUT("p1p2 ", p1, p2);
//        dfs2(p1, p2);
//        dfs2(p2, p1);
//        dfs3(p1, p2, h[p2]);
//        dfs3(p2, p1, h[p1]);
//    }
//    sort(ans.begin(), ans.end());
//    ans.erase(unique(ans.begin(), ans.end()), ans.end());
//    printf("%u\n", ans.size());
//}

pii h[N];
vector<pii> hs[N];

void itera(){
    rep1(u, n) {
        hs[u].clear();
        for(int v : g[u]) hs[u].push_back(h[v]);
        sort(hs[u].begin(), hs[u].end());
    }
    rep1(u, n){
        pii t = pii(5, 7);
        for(unsigned i = 0; i < hs[u].size(); ++i) t = t * base + hs[u][i] * pii(i + 1, i + 1);
        h[u] = h[u] * base2 + t;
    }
}

vector<pii> ans;
void solve(){
    rep1(i, n) h[i] = pii(2, 3);
    for(int c = 23; c--; ) itera();
    ans.clear();
    rep1(i, n) if(g[i].size() < 4) ans.push_back(h[i]);
    sort(ans.begin(), ans.end());
    ans.erase(unique(ans.begin(), ans.end()), ans.end());
    printf("%u\n", ans.size());
}

int main(){
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    srand(time(NULL));
    int u, v;
    while(scan(n)){
        rep1(i, n) g[i].clear();
        rep(i, n - 1){
            scan(u, v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        solve();
//        break;
    }
    return 0;
}

#ifndef __clang__
#pragma GCC optimize ("-O3")
#endif
#ifdef ONLINE_JUDGE
#define NDEBUG 1
#endif
#define _GLIBCXX_USE_CXX11_ABI 0
#include <stdio.h>
#include <bits/stdc++.h>

#define DESTRUCT2(p, a, b)                      \
  auto a = get<0>(p);                           \
  auto b = get<1>(p);

#define DESTRUCT3(p, a, b, c)                   \
  auto a = get<0>(p);                           \
  auto b = get<1>(p);                           \
  auto c = get<2>(p);

#define DESTRUCT4(p, a, b, c, d)                \
  auto a = get<0>(p);                           \
  auto b = get<1>(p);                           \
  auto c = get<2>(p);                           \
  auto d = get<3>(p);

#define FOR(i, n)     for(lli i = 0; i < (lli)(n); ++i)
#define FORU(i, j, k) for(lli i = (j); i <= (lli)(k); ++i)
#define FORD(i, j, k) for(lli i = (j); i >= (lli)(k); --i)

#define SQ(x) ((x)*(x))

#define all(x) begin(x), end(x)
#define rall(x) rbegin(x), rend(x)
#define mp make_pair
#define mt make_tuple
#define pb push_back
#define eb emplace_back

using namespace std;

template<typename... As>
struct tpl : public std::tuple<As...> {
  using std::tuple<As...>::tuple;

  template<typename T = tuple<As...> >
  typename tuple_element<0, T>::type const&
  x() const { return get<0>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<0, T>::type&
  x() { return get<0>(*this); }

  template<typename T = tuple<As...> >
  typename tuple_element<1, T>::type const&
  y() const { return get<1>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<1, T>::type&
  y() { return get<1>(*this); }

  template<typename T = tuple<As...> >
  typename tuple_element<2, T>::type const&
  z() const { return get<2>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<2, T>::type&
  z() { return get<2>(*this); }

  template<typename T = tuple<As...> >
  typename tuple_element<3, T>::type const&
  w() const { return get<3>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<3, T>::type&
  w() { return get<3>(*this); }
};

using lli   = long long int;
using llu   = long long unsigned;

using pii   = tpl<lli, lli>;
using piii  = tpl<lli, lli, lli>;
using piiii = tpl<lli, lli, lli, lli>;
using vi    = vector<lli>;
using vii   = vector<pii>;
using viii  = vector<piii>;
using vvi   = vector<vi>;
using vvii  = vector<vii>;
using vviii = vector<viii>;

template<class T>
using min_queue = priority_queue<T, vector<T>, greater<T> >;
template<class T>
using max_queue = priority_queue<T>;

template<size_t... I>
struct my_index_sequence {
  using type = my_index_sequence;
  static constexpr array<size_t, sizeof...(I)> value = { {I}... };
};

namespace my_index_sequence_detail {
  template<typename I, typename J> struct concat;
  template<size_t... I, size_t... J>
  struct concat<my_index_sequence<I...>, my_index_sequence<J...> > :
    my_index_sequence<I..., (sizeof...(I)+J)...> { };
  template<size_t N> struct make_index_sequence :
    concat<typename make_index_sequence<N/2>::type, typename make_index_sequence<N-N/2>::type>::type { };
  template <> struct make_index_sequence<0> : my_index_sequence<>{};
  template <> struct make_index_sequence<1> : my_index_sequence<0>{};
}

template<class... A>
using my_index_sequence_for = typename my_index_sequence_detail::make_index_sequence<sizeof...(A)>::type;

template<class T, size_t... I>
void print_tuple(ostream& s, T const& a, my_index_sequence<I...>){
  using swallow = int[];
  (void)swallow{0, (void(s << (I == 0? "" : ", ") << get<I>(a)), 0)...};
}

template<class T>
ostream& print_collection(ostream& s, T const& a){
  s << '[';
  for(auto it = begin(a); it != end(a); ++it){
    s << *it;
    if(it != prev(end(a))) s << " ";
  }
  return s << ']';
}

template<class... A>
ostream& operator<<(ostream& s, tpl<A...> const& a){
  s << '(';
  print_tuple(s, a, my_index_sequence_for<A...>{});
  return s << ')';
}

template<class... A>
ostream& operator<<(ostream& s, tuple<A...> const& a){
  s << '(';
  print_tuple(s, a, my_index_sequence_for<A...>{});
  return s << ')';
}

template<class A, class B>
ostream& operator<<(ostream& s, pair<A, B> const& a){
  return s << "(" << get<0>(a) << ", " << get<1>(a) << ")";
}

template<class T, size_t I>
ostream& operator<<(ostream& s, array<T, I> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, vector<T> const& a) { return print_collection(s, a); }
template<class T, class U>
ostream& operator<<(ostream& s, multimap<T, U> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, multiset<T> const& a) { return print_collection(s, a); }
template<class T, class U>
ostream& operator<<(ostream& s, map<T, U> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, set<T> const& a) { return print_collection(s, a); }

namespace std {
  namespace {
    template <class T>
    inline void hash_combine(size_t& seed, T const& v) {
      std::hash<T> hasher;
      const std::size_t kMul = 0x9ddfea08eb382d69ULL;
      std::size_t a = (hasher(v) ^ seed) * kMul;
      a ^= (a >> 47);
      std::size_t b = (seed ^ a) * kMul;
      b ^= (b >> 47);
      seed = b * kMul;
    }
    template <class Tuple, size_t Index = tuple_size<Tuple>::value - 1>
    struct HashValueImpl {
      static void apply(size_t& seed, Tuple const& tuple) {
        HashValueImpl<Tuple, Index-1>::apply(seed, tuple);
        hash_combine(seed, get<Index>(tuple));
      }
    };
    template <class Tuple>
    struct HashValueImpl<Tuple, 0> {
      static void apply(size_t& seed, Tuple const& tuple) {
        hash_combine(seed, get<0>(tuple));
      }
    };
  }
  template <typename ... TT>
  struct hash<tuple<TT...>> {
    size_t operator()(tuple<TT...> const& tt) const {
      size_t seed = 0;
      HashValueImpl<tuple<TT...> >::apply(seed, tt);
      return seed;
    }
  };
  template <typename ... TT>
  struct hash<tpl<TT...>> {
    size_t operator()(tpl<TT...> const& tt) const {
      size_t seed = 0;
      HashValueImpl<tuple<TT...> >::apply(seed, tt);
      return seed;
    }
  };
}

int read_positive(){
  char c; int x=0;
  do { c = getchar(); } while(c<'0' || c>'9');
  while(c>='0'&&c<='9') {
    x=10*x+(c-'0');
    c = getchar();
  }
  return x;
}

//------------------------------------------------------------------------------

// --- BEGIN SNIPPET TREE ---

struct treechain {
  lli root = -1;
  lli size = 0;
  vi  nodes;

  treechain() { }

#ifdef WITH_HLD
  using segment = segment_tree; // segment tree / bit / other
  segment A;
  void build(){ A = segment(size); /* make segment tree */ }
#else
  void build(){ }
#endif
};

struct tree {
  lli n;
  vvi G;

  vi parent;
  vi depth;
  vi size;
  vi order, rorder;
  vii eorder;

  vector<treechain> chains;
  vector<lli>       chain;
  vector<lli>       chainIx;

  tree(lli n_) : n(n_), G(n) { }

  void read_graph(istream& input = cin) {
    FOR(i, n-1) {
      lli u, v; input >> u >> v;
      u -= 1; v -= 1;
      G[u].pb(v); G[v].pb(u);
    }
  }

  void calcparent() {
    if(parent.empty()) {
      parent.assign(n, -1);
      order.clear();
      vi E(n, 0);
      vector<lli> Q; Q.pb(0);
      while(!Q.empty()) {
        lli i = Q.back(); Q.pop_back();
        order.pb(i);
        E[i] = 1;
        for(auto j : G[i]) if(!E[j]) {
            parent[j] = i;
            Q.pb(j);
          }
      }
      rorder = order;
      reverse(all(rorder));
    }
  }

  template<typename T>
  inline vector<vector<T> > makeEVec(T const& def = T()) {
    vector<vector<T> > v(n); FOR(i, n) v[i].assign(G[i].size(), def);
    return v;
  }

  void calceorder() {
    if(eorder.empty()) {
      vvi E = makeEVec(0ll);
      FOR(i, n) FOR(j_, G[i].size()) if(!E[i][j_]) {
        vii Q; Q.pb(mt(i,j_));
        vii tmp;
        while(!Q.empty()) {
          DESTRUCT2(Q.back(), i, j_); Q.pop_back();
          tmp.pb(mt(i, j_)); E[i][j_] = 1;
          lli j = G[i][j_];
          FOR(k_, G[j].size()) if(G[j][k_] != i && !E[j][k_]) Q.pb(mt(j, k_));
        }
        reverse(all(tmp));
        eorder.insert(end(eorder), all(tmp));
      }
    }
  }

  void calcsize() {
    calcparent();
    if(size.empty()) {
      size.assign(n, 1);
      for(auto i : rorder) if(parent[i]!=-1) size[parent[i]] += size[i];
    }
  }

  void calcdepth() {
    calcparent();
    if(depth.empty()) {
      depth.assign(n, 0);
      for(auto i : order) if(parent[i] != -1) depth[i] = depth[parent[i]] + 1;
    }
  }

  void calchld() {
    if(chains.empty()){
      calcsize();
      calcdepth();

      chain.assign(n, -1);
      for(auto i : rorder) {
        lli best = -1;
        for(auto j : G[i]) if(j != parent[i]) {
            if(best == -1 || size[j] > size[best]) best = j;
          }
        if(best == -1) {
          chain[i] = chains.size();
          chains.eb();
        }else{
          chain[i] = chain[best];
        }
        chains[chain[i]].size += 1;
      }

      chainIx.assign(n, -1);
      for(auto i : order) {
        if(parent[i]==-1 || chain[i] != chain[parent[i]]) chains[chain[i]].root = i;
        chainIx[i] = chains[chain[i]].nodes.size();
        chains[chain[i]].nodes.pb(i);
      };

      for(auto& c : chains) c.build();
    }
  }

  // O(log n) lca
  lli lca(lli a, lli b) {
    calchld();
    while(chain[a] != chain[b]) {
      if(depth[chains[chain[a]].root]>depth[chains[chain[b]].root]) {
        a = parent[chains[chain[a]].root];
      }else{
        b = parent[chains[chain[b]].root];
      }
    }
    if(depth[a]<depth[b]) return a; else return b;
  }

  lli dist(lli a, lli b) {
    calchld();
    return depth[a]+depth[b]-2*depth[lca(a, b)];
  }

#ifdef WITH_HLD
  // arguments to f :
  // segment, segment range, range in path from a to b (a = 0, b = dist(a, b))
  // the segment range is increasing
  // the range in path can be decreasing
  // O (log² n)
  void hld_query(lli a, lli b, function<void(treechain::segment&, lli, lli, lli, lli)> f) {
    calchld();
    lli from = 0, to = dist(a, b);
    while(chain[a] != chain[b]) {
      if(depth[chains[chain[a]].root]>depth[chains[chain[b]].root]) {
        lli a_ = parent[chains[chain[a]].root];
        lli d = depth[a]-depth[a_];
        f(chains[chain[a]].A, 0, chainIx[a], from+d, from);
        from += d;
        a = a_;
      }else{
        lli b_ = parent[chains[chain[b]].root];
        lli d = depth[b]-depth[b_];
        f(chains[chain[b]].A, 0, chainIx[b], to-d, to);
        to -= d;
        b = b_;
      }
    }
    if(depth[a]<depth[b]) {
      f(chains[chain[a]].A, chainIx[a]+1, chainIx[b], from, to);
    }else{
      f(chains[chain[a]].A, chainIx[b]+1, chainIx[a], from, to);
    }
  }
#endif
};

// --- END SNIPPET TREE ---

const lli MOD = 1e9+7;
const lli P = 239;

const int NN = 16;
using T = array<size_t, NN>;

T def;

T combine(T const& a, T const& b) {
  T r = a;
  FOR(i, NN) hash_combine(r[i], b[i]);
  return r;
}

int main(int, char**){
  ios::sync_with_stdio(0); cin.tie(0);
  srand(time(0)); FOR(i, NN) def[i] = rand()*RAND_MAX+rand();
  int n; cin >> n;
  tree t(n); t.read_graph();
  t.calceorder();
  auto v = t.makeEVec<T>();
  for(auto p : t.eorder) {
    DESTRUCT2(p, i, j_); int j = t.G[i][j_];
    v[i][j_] = def;
    vector<T> cs;
    FOR(k_, t.G[j].size()) {
      int k = t.G[j][k_];
      if(k == i) continue;
      cs.pb(v[j][k_]);
    }
    sort(all(cs));
    for(T hh : cs) v[i][j_] = combine(v[i][j_], hh);
  }
  set<T> S;
  FOR(i, n) if(t.G[i].size() < 4) {
    T h = def;
    vector<T> cs;
    FOR(j_, t.G[i].size()) cs.pb(v[i][j_]);
    sort(all(cs));
    for(T hh : cs) h = combine(h, hh);
    S.insert(h);
  }
  cout << S.size() << endl;
  return 0;
}

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

const int mod = 1e9+9;
const int MAXN = 1e5 + 10;
const int p = 257;
const int q = 1e9+7;
multiset<int> H[MAXN];
vector<int> g[MAXN];
int n;

int add(int a, int b) {
	return (a+b)%mod;
}

int mul(long long a, long long b) {
	return a*b%mod;
}

int hashing(multiset<int> H) {
	int h = 0;
	for (int v : H) {
		h = add(add(mul(h, p), v), q);
	}
	return h;
}

void dfs(int x, int p) {
	for (int v : g[x]) {
		if (v == p) continue;
		dfs(v, x);
		H[x].insert(hashing(H[v]));
	}
	for (int i = H[x].size(); i < 4; ++i) {
		H[x].insert(mod-1);
	}
}

set<int> Set;
void dfsRoot(int x, int p) {
	if (p) {
		multiset<int> aux = H[p];
		aux.erase(aux.lower_bound(hashing(H[x])));
		aux.insert(mod-1);
		H[x].erase(H[x].lower_bound(mod-1));
		H[x].insert(hashing(aux));
	}
	if (g[x].size() != 4)
		Set.insert(hashing(H[x]));
	for (int v : g[x])
		if (v != p)
			dfsRoot(v, x);
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i < n; ++i) {
		int u, v;
		scanf ("%d %d",  &u, &v);
		g[u].emplace_back(v);
		g[v].emplace_back(u);
	}

	dfs(1, 0);
	dfsRoot(1, 0);
	cout << Set.size() << endl;

	return 0;
}

#include <bits/stdc++.h>

#define INF_MAX 2147483647
#define INF_MIN -2147483647
#define INF_LL 9223372036854775807LL
#define INF 1000000000
#define EPS 1e-8
#define LL long long
#define mod 1000000007
#define pb push_back
#define mp make_pair
#define f first
#define s second
#define setzero(a) memset(a,0,sizeof(a))
#define setdp(a) memset(a,-1,sizeof(a))
#define bits(a) __builtin_popcount(a)

using namespace std;

vector<pair<int, int> > tree[100005];
pair<int, int> DP[200005];
bool v[200005];

const int b1 = 29, m1 = mod;
const int b2 = 31, m2 = mod + 2;

pair<int, int> solve(int node, int parent, int id)
{
  pair<int, int> &temp = DP[id];
  if(v[id]) return temp;
  v[id] = true;
  vector<pair<int, int> > v;
  for(auto p : tree[node])
  {
    if(parent == p.f) continue;
    v.pb(solve(p.f, node, p.s));
  }
  temp = mp(1, 1);
  sort(v.begin(), v.end());
  for(int i=0;i<v.size();i++)
  {
    temp.f = (temp.f * 1LL * b1 + v[i].f) % m1;
    swap(v[i].f, v[i].s);
  }
  sort(v.begin(), v.end());
  for(int i=0;i<v.size();i++)
    temp.s = (temp.s * 1LL * b2 + v[i].f) % m2;
  return temp;
}

int main()
{
  int n, x, y;
  cin >> n;
  for(int i=0;i<n-1;i++)
  {
    scanf("%d %d", &x, &y);
    tree[x].pb(mp(y, i*2));
    tree[y].pb(mp(x, i*2+1));
  }
  set<pair<int, int> > s;
  for(int i=1;i<=n;i++)
  {
    if(tree[i].size() == 4) continue;
    vector<pair<int, int> > v;
    for(auto p : tree[i])
      v.pb(solve(p.f, i, p.s));
    pair<int, int> temp = mp(1, 1);
    sort(v.begin(), v.end());
    for(int i=0;i<v.size();i++)
    {
      temp.f = (temp.f * 1LL * b1 + v[i].f) % m1;
      swap(v[i].f, v[i].s);
    }
    sort(v.begin(), v.end());
    for(int i=0;i<v.size();i++)
      temp.s = (temp.s * 1LL * b2 + v[i].f) % m2;
    s.insert(temp);
  }
  cout << s.size();
  return 0;
}

#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
const int N=1e5+5;
struct edge{
	int link,next;
}e[N<<1];
int tot,n,ok[N],head[N],cnt,deg[N];
inline int read(){int x=0,f=1,ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}
inline void write(int x){if (x<0) putchar('-'),x=-x; if (x>=10) write(x/10); putchar(x%10+'0');}
inline void writeln(int x){write(x); puts("");}
inline void add_edge(int u,int v){
	e[++tot]=(edge){v,head[u]}; head[u]=tot;
}
inline void insert(int u,int v){
	add_edge(u,v); add_edge(v,u);
	deg[u]++; deg[v]++;
}
inline void init(){
	n=read();
	for (int i=1;i<n;i++){
		int u=read(),v=read();
		insert(u,v);
	}
}
map<vector<int >,int >mp;
map<int ,int >dp[N];
inline int dfs(int u,int fa){
	vector<int> vec;
	if (dp[u][fa]) return dp[u][fa];
	for (int i=head[u];i;i=e[i].next){
		int v=e[i].link;
		if (v!=fa){
			vec.push_back(dfs(v,u));
		}
	}
	sort(vec.begin(),vec.end());
	if (!mp[vec]) mp[vec]=++cnt;
	return dp[u][fa]=mp[vec];
}
inline void solve(){
	for (int i=1;i<=n;i++){
		if (deg[i]<4) {
			ok[dfs(i,0)]=1;
		}
	}
	int ans=0;
	for (int i=1;i<=cnt;i++) ans+=ok[i];
	writeln(ans);
}
int main(){
	init(); solve();
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 200005;
const int Q = 1e9 + 7;
int n , pre[N] , mcnt;
struct edge {
    int x , next;
} e[N << 1];

int deg[N];
bool f[N << 1];
int size[N << 1];
int Hash[N << 1];
int power[N * 4];
void addedge(int x , int y) {
    e[mcnt] = (edge) {y , pre[x]} , pre[x] = mcnt ++;
}
int dfs(int o) {
    if (f[o]) {
        return Hash[o];
    } f[o] = 1;
    int x = e[o].x;
    size[o] = 1;
    vector< pair<int , int> > V;
    for (int i = pre[x] ; ~i ; i = e[i].next) {
        int y = e[i].x;
        if ((i ^ o) != 1) {
            V.push_back(make_pair(dfs(i) , i));
            size[o] += size[i];
        }
    }
    sort(V.begin() , V.end());
    Hash[o] = 1;
    for (auto it : V) {
        int y = it.second;
        Hash[o] = ((LL)Hash[o] * power[size[y] * 2] + Hash[y]) % Q;
    }
    Hash[o] = ((LL)Hash[o] * 3 + 2) % Q;
    return Hash[o];
}

int main() {
    power[0] = 1;
    for (int i = 1 ; i < N * 4 ; ++ i) {
        power[i] = (LL)power[i - 1] * 3 % Q;
    }
    scanf("%d" , &n);
    memset(pre , -1,  sizeof(pre));
    for (int i = 0 ; i < n - 1 ; ++ i) {
        int x , y;
        scanf("%d%d" , &x , &y);
        addedge(x , y);
        addedge(y , x);
        ++ deg[x];
        ++ deg[y];
    }
    for (int i = 1 ; i <= n ; ++ i) {
        addedge(i + n , i);
    }
    vector<int> res;
    // for (int i = 0 ; i < mcnt ; ++ i) cout << i << ' ' << dfs(i) << endl;
    set<int> P;
    for (int i = 1 ; i <= n ; ++ i) {
        if (deg[i] + 1 <= 4) {
            int j = n * 2 + i - 3;
            //printf("%d %d\n" , j , e[j].x);
            P.insert(dfs(j));
            //cout << j << ' ' << dfs(j) << endl;
        }
    }
    cout << P.size() << endl;
}

#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <map>
#include <set>

using namespace std;

typedef long long LL;

const int maxn = 100005;
const int mod1 = 9191891;
const int mod2 = 1e9+7;

struct edge
{
	int to;
	int nxt;
} e[maxn<<1];

int first[maxn];
int d[maxn];

int nowm;
inline void add_edge(int from, int to)
{
	d[from]++;
	e[++nowm].nxt = first[from];
	first[from] = nowm;
	e[nowm].to = to;
	d[to]++;
	e[++nowm].nxt = first[to];
	first[to] = nowm;
	e[nowm].to = from;
}

struct JYT
{
	int x, y;

	inline JYT operator + (const JYT& other) const
	{
		JYT ans;
		ans.x = (x+other.x)%mod1;
		ans.y = (y+other.y)%mod2;
		return ans;
	}

	inline JYT operator * (const JYT& other) const
	{
		JYT ans;
		ans.x = (x*other.x)%mod1;
		ans.y = (y*other.y)%mod2;
		return ans;
	}

	inline bool operator < (const JYT& other) const
	{
		return x < other.x || (x == other.x && y < other.y);
	}
};

JYT Q;

map<int, JYT> mmap[maxn];
set<JYT> S;

inline JYT dfs(int x, int F)
{
	if(mmap[x].find(F) != mmap[x].end())
		return mmap[x][F];
	JYT ans, t;
	ans = Q;
	for(int i = first[x]; i; i = e[i].nxt)
	{
		if(e[i].to != F)
		{
			t = dfs(e[i].to, x);
			ans = ans + t*t*t;
		}
	}
	return mmap[x][F] = ans;
}

int main()
{
//	srand((unsigned)time(NULL));
	Q.x = 527468;
	Q.y = 687;
	int n;
	scanf("%d", &n);
	for(int i = 1, f, t; i < n; ++i)
	{
		scanf("%d%d", &f, &t);
		add_edge(f, t);
	}
	int ans = 0;
	for(int i = 1; i <= n; ++i)
		if(d[i] < 4)
		{
			JYT tmp = dfs(i, 0);
			if(S.find(tmp) == S.end())
			{
				ans++;
				S.insert(tmp);
			}
		}
	printf("%d", ans);
	return 0;
}

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
const int N = 1e5, K = 4;
vector<int> g[N], b;
int a[N];
int get_index(const vector<int> x)
{
	static map<vector<int>, int> m;
	static int cnt;
	if (m.find(x) == m.end()) m[x] = cnt++;
	return m[x];
}
void dfs_pre(int u, int fa)
{
	vector<int> x;
	for (int v : g[u])
		if (v != fa)
		{
			dfs_pre(v, u);
			x.push_back(a[v]);
		}
	sort(x.begin(), x.end());
	a[u] = get_index(x);
}
void dfs(int u, int fa)
{
	vector<int> x;
	if (g[u].size() < K)
	{
		for (int v : g[u])
			if (v != fa) x.push_back(a[v]);
		sort(x.begin(), x.end());
		b.push_back(get_index(x));
	}
	sort(g[u].begin(), g[u].end(), [](int x, int y) { return a[x] < a[y]; });
	x.clear();
	for (int i = 1; i < g[u].size(); i++) x.push_back(a[g[u][i]]);
	for (int i = 0; i < g[u].size(); i++)
	{
		if (i > 0) x[i - 1] = a[g[u][i]];
		if (g[u][i] != fa)
		{
			a[u] = get_index(x);
			dfs(g[u][i], u);
		}
	}
}
int main()
{
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	for (int i = 0; i < n - 1; i++)
	{
		int x, y;
		cin >> x >> y;
		x--, y--;
		g[x].push_back(y);
		g[y].push_back(x);
	}
	dfs_pre(0, -1);
	dfs(0, -1);
	sort(b.begin(), b.end());
	int cnt = 0;
	for (int i = 0; i < b.size(); i++)
		if (i == 0 || b[i] != b[i - 1]) cnt++;
	cout << cnt << endl;
}

#include <bits/stdc++.h>
#define LL long long
#define pii pair <LL, LL>
#define xx first
#define yy second
using namespace std;

const int N = 100100;
const LL A = 23, B = 17, C = 233, D = 19, mod1 = 1e9 + 7, mod2 = 1e9 + 9;

map <pii, pii> mp;
vector <int> g[N];
int u[N], v[N];

pii dfs (int u, int fa) {
    if (mp.find (pii (u, fa)) != mp.end()) return mp[pii (u, fa)];
    vector <pii> tmp;
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if (v == fa) continue;
        tmp.push_back (dfs (v, u));
    }
    sort (tmp.begin(), tmp.end());
    LL h1 = 0, h2 = 0;
    for (int i = 0; i < tmp.size(); i++) {
        h1 = (((h1 * A + B) ^ tmp[i].xx) + C) % mod1;
        h2 = (((h2 * A + B) ^ tmp[i].yy) + C) % mod2;
    }
    h1 += D;
    h2 += D;
    return mp[pii (u, fa)] = pii (h1, h2);
}

int main () {
//    freopen ("in", "r", stdin);
    int n;
    cin >> n;
    for (int i = 1; i < n; i++) {
        scanf ("%d%d", &u[i], &v[i]);
        g[u[i]].push_back (v[i]);
        g[v[i]].push_back (u[i]);
    }
    set <pii> st;
    for (int i = 1; i <= n; i++) {
        if (g[u[i]].size() < 4) st.insert (dfs (u[i], 0));
//        if (g[v[i]].size() < 4) st.insert (dfs (v[i], u[i]));
    }
    cout << st.size() << endl;
}

#include<bits/stdc++.h>

#define pb push_back
#define sz(a) ((int)a.size())
#define x first
#define y second
#define bpt(x) (__builtin_popcount(x))
#define bit(x, y) (((x)>>(y))&1)
#define bclz(x) (__builtin_clz(x))
#define bctz(x) (__builtin_ctz(x))

using namespace std;

using uint = unsigned long long;

typedef double DO;
typedef long long INT;
typedef pair<int, int> pii;
typedef vector<int> VI;

template<typename T, typename U> inline void smin(T &a, U b) {if(a>b) a=b;}
template<typename T, typename U> inline void smax(T &a, U b) {if(a<b) a=b;}

template<class T>inline void gn(T &x) {char c, sg=0; while (c=getchar(), (c>'9' || c<'0') && c!='-');for((c=='-'?sg=1, c=getchar():0), x=0; c>='0' && c<='9'; c=getchar()) x=(x<<1)+(x<<3)+c-'0';if (sg) x=-x;}
template<class T>inline void print(T x) {if (x<0) {putchar('-');return print(-x);}if (x<10) {putchar('0'+x);return;} print(x/10);putchar(x%10+'0');}
template <class T> inline void println(T x) {print(x); putchar('\n');}

int power(int a, int b, int m, int ans=1) {
	for(; b; b>>=1, a=1LL*a*a%m) if(b&1) ans=1LL*ans*a%m;
	return ans;
}

#define NN 100111
const int hmod = 4;
VI adj[NN];
uint val[NN];
uint jia[NN];
uint up[NN];
int n;
int son[NN];
vector<uint> vec[NN];
int nn;
int p[NN];

void dfs(int u, int fa=0) {
	son[u]=1;
	p[u] = fa;
	for(int v : adj[u]) {
		if(v == fa) continue;
		dfs(v, u);
		son[u]+=son[v];
		vec[u].pb(val[v]);
	}
	vec[u].pb(son[u]);
	vec[u].pb(sz(adj[u]));
	sort(vec[u].begin(), vec[u].end());
	for(uint &v : vec[u]) {
		val[u]=val[u]*hmod+v;
	}
}

set<uint> s;
void rdfs(int u, int fa=0) {
	if(fa) {
		vec[u].clear();
		for(int v : adj[fa]) if(v != p[fa] and v != u) {
			vec[u].pb(val[v]);
		}
		if(p[fa]) vec[u].pb(up[p[fa]]);
		vec[u].pb(sz(adj[fa]));
		vec[u].pb(n-son[u]);
		sort(vec[u].begin(), vec[u].end());

		up[fa]=0;
		for(uint &v : vec[u]) {
			up[fa]=up[fa]*hmod+v;
		}
		vec[u].clear();
		for(int v : adj[u]) {
			if(v==fa) vec[u].pb(up[fa]);
			else vec[u].pb(val[v]);
		}
		vec[u].pb(sz(adj[u]));
		vec[u].pb(n);
		sort(vec[u].begin(), vec[u].end());
		jia[u]=0;
		for(uint &v : vec[u]) {
			jia[u]=jia[u]*hmod+v;
		}

	} else jia[u]=val[u];
	if(sz(adj[u])<4) s.insert(jia[u]);
	for(int v : adj[u]) if(v!=fa) {
		rdfs(v, u);
	}

}
int solve() {
	cin >> n;
	for(int i=0; i<n-1; i++) {
		int u, v; gn(u); gn(v);
		adj[u].pb(v); adj[v].pb(u);
	}
	int root;
	srand(time(0));
	root=rand()%n+1;
	root=2;
	dfs(root);
	rdfs(root);
	cout << sz(s) << endl;
}

int main() {
#ifndef	ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	solve();
	return 0;
}

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 210000;

int n;
int oke[maxn],okp[maxn];
struct edge{int y,nex;}a[maxn<<1]; int len,fir[maxn];
inline void ins(const int x,const int y){a[++len]=(edge){y,fir[x]};fir[x]=len;}

int siz[maxn],mxs[maxn];
void dfs(const int x,const int fa)
{
	siz[x]=1;
	for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa)
	{
		dfs(y,x);
		siz[x]+=siz[y];
		mxs[x]=max(mxs[x],siz[y]);
	}
}
int root,t1,t2;
int d[maxn],f[maxn],f2[maxn];
bool cmp(const int x,const int y){return f[x]==f[y]?f2[x]<f2[y]:f[x]<f[y];}
int t[maxn],tp;
void Hash(const int x,const int fa)
{
	siz[x]=1;
	for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa&&oke[k]) Hash(y,x),siz[x]+=siz[y];
	tp=0; for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa&&oke[k]) t[++tp]=y;
	sort(t+1,t+tp+1,cmp);
	d[x]=tp+(fa!=0);
	f[x]=1,f2[x]=0;
	for(int i=1;i<=tp;i++)
	{
		int y=t[i];
		f[x]=f[x]*(siz[y]+1)*f[y];
		f2[x]=f2[x]+(siz[y]+2)*(f2[y]+1);
	}
}
int ans[maxn];
void cal(const int x,const int fa)
{
	if(okp[x]&&d[x]<4) ans[x]++;
	for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa&&oke[k]) cal(y,x);
	tp=0; for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa&&oke[k]) t[++tp]=y;
	sort(t+1,t+tp+1,cmp);
	for(int i=1;i<=tp;i++)
	{
		int y=t[i],ty=t[i-1];
		if(f[y]!=f[ty]||f2[y]!=f2[ty]) ans[x]+=ans[y];
	}
}

int main()
{
	//freopen("tmp.in","r",stdin);
	//freopen("tmp.out","w",stdout);

	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int x,y; scanf("%d%d",&x,&y);
		ins(x,y),ins(y,x);
	}
	dfs(1,0);
	for(int i=1;i<=n;i++) if(mxs[i]*2<=n&&(n-siz[i])*2<=n)
	{
		if(!t1) t1=i;
		else t2=i;
	}
	for(int i=1;i<=len;i++) oke[i]=1;
	for(int i=1;i<=n;i++) okp[i]=1;
	if(t2)
	{
		for(int k=fir[t1],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y==t2) oke[k]=0;
		for(int k=fir[t2],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y==t1) oke[k]=0;
		okp[root=++n]=0; ins(root,t1),ins(root,t2);
	}
	else root=t1;

	Hash(root,0);
	cal(root,0);
	printf("%d\n",ans[root]);

	return 0;
}

#include <iostream>
#include <fstream>
#include <vector>
#include <stack>
#include <queue>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <map>
#include <set>

using namespace std;

typedef long long ll;
typedef pair<int,int> PP;

/*
    freopen("input","r",stdin);
    freopen("output","w",stdout);
*/

vector<vector<int> > G;

map<pair<int, int>, ll> H;

map<vector<ll>, ll> R;

ll cal(int x, int p) {
	pair<int, int> r;
	r.first = x;
	r.second = p;
	if (H.find(r) != H.end()) return H[r];
	vector<ll> num;
	for (int i = 0;i < G[x].size();i++) {
		int j = G[x][i];
		if (j == p) continue;
		num.push_back(cal(j, x));
	}
	ll ans = 0;
	if (R.find(num) != R.end()) {
		ans = R[num];
	}
	else {
		R[num] = R.size();
		ans = R[num];
	}
	H[r] = ans;
	return ans;
}

int main() {
    ios::sync_with_stdio(false);
    int n;
    scanf("%d", &n);
    G.resize(n + 1);
    for (int i = 1;i < n;i++) {
    	int a, b;
    	scanf("%d%d", &a, &b);
    	G[a].push_back(b);
    	G[b].push_back(a);
    }
    unordered_set<ll> R;
    for (int i = 1;i <= n;i++) {
    	if (G[i].size() == 4) continue;
    	ll ans = cal(i, 0);
    	R.insert(ans);
    }
    cout << R.size() << endl;
    return 0;
}

#include<bits/stdc++.h>

#define pb push_back
#define sz(a) ((int)a.size())
#define x first
#define y second
#define bpt(x) (__builtin_popcount(x))
#define bit(x, y) (((x)>>(y))&1)
#define bclz(x) (__builtin_clz(x))
#define bctz(x) (__builtin_ctz(x))

using namespace std;

using uint = unsigned long long;

typedef double DO;
typedef long long INT;
typedef pair<int, int> pii;
typedef vector<int> VI;

template<typename T, typename U> inline void smin(T &a, U b) {if(a>b) a=b;}
template<typename T, typename U> inline void smax(T &a, U b) {if(a<b) a=b;}

template<class T>inline void gn(T &x) {char c, sg=0; while (c=getchar(), (c>'9' || c<'0') && c!='-');for((c=='-'?sg=1, c=getchar():0), x=0; c>='0' && c<='9'; c=getchar()) x=(x<<1)+(x<<3)+c-'0';if (sg) x=-x;}
template<class T>inline void print(T x) {if (x<0) {putchar('-');return print(-x);}if (x<10) {putchar('0'+x);return;} print(x/10);putchar(x%10+'0');}
template <class T> inline void println(T x) {print(x); putchar('\n');}

int power(int a, int b, int m, int ans=1) {
	for(; b; b>>=1, a=1LL*a*a%m) if(b&1) ans=1LL*ans*a%m;
	return ans;
}

#define NN 100111
const int hmod = 999999983;
VI adj[NN];
uint val[NN];
uint jia[NN];
uint up[NN];
int n;
int son[NN];
vector<uint> vec[NN];
int nn;
int p[NN];

void dfs(int u, int fa=0) {
	son[u]=1;
	p[u] = fa;
	for(int v : adj[u]) {
		if(v == fa) continue;
		dfs(v, u);
		son[u]+=son[v];
		vec[u].pb(val[v]);
	}
	vec[u].pb(son[u]);
	vec[u].pb(sz(adj[u]));
	sort(vec[u].begin(), vec[u].end());
	for(uint &v : vec[u]) {
		val[u]=val[u]*hmod+v;
	}
}

set<uint> s;
void rdfs(int u, int fa=0) {
	if(fa) {
		vec[u].clear();
		for(int v : adj[fa]) if(v != p[fa] and v != u) {
			vec[u].pb(val[v]);
		}
		if(p[fa]) vec[u].pb(up[p[fa]]);
		vec[u].pb(sz(adj[fa]));
		vec[u].pb(n-son[u]);
		sort(vec[u].begin(), vec[u].end());

		up[fa]=0;
		for(uint &v : vec[u]) {
			up[fa]=up[fa]*hmod+v;
		}
		vec[u].clear();
		for(int v : adj[u]) {
			if(v==fa) vec[u].pb(up[fa]);
			else vec[u].pb(val[v]);
		}
		vec[u].pb(sz(adj[u]));
		vec[u].pb(n);
		sort(vec[u].begin(), vec[u].end());
		jia[u]=0;
		for(uint &v : vec[u]) {
			jia[u]=jia[u]*hmod+v;
		}

	} else jia[u]=val[u];
	if(sz(adj[u])<4) s.insert(jia[u]);
	for(int v : adj[u]) if(v!=fa) {
		rdfs(v, u);
	}

}
int solve() {
	cin >> n;
	for(int i=0; i<n-1; i++) {
		int u, v; gn(u); gn(v);
		adj[u].pb(v); adj[v].pb(u);
	}
	int root;
	srand(time(0));
	root=rand()%n+1;
	dfs(root);
	rdfs(root);
	cout << sz(s) << endl;
}

int main() {
#ifndef	ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	solve();
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define Q 19260817
#define mod 993729403
#define mod2 806053187
#define Q2 20030112
#define mod3 998244353
#define Q3 42345457
#define maxn 100001
int head[maxn],nxt[maxn<<2],ver[maxn<<2],tot;int n;int d[maxn];
map<pair<int,int>,int> hash,hash2,hash3;
map<int,bool> mp,mp2,mp3;
inline int cube(int x){return x*x%mod*x%mod;}
inline int cube2(int x){return x*x%mod2*x%mod2;}
inline int cube3(int x){return x*x%mod3*x%mod3;}
inline void addedge(int a,int b)
{
	nxt[++tot]=head[a];ver[tot]=b;head[a]=tot;d[a]++;
	nxt[++tot]=head[b];ver[tot]=a;head[b]=tot;d[b]++;
}
inline int calc_hash(int x,int fa)
{
	if(hash[make_pair(x,fa)]) return hash[make_pair(x,fa)];
	int res=Q;
	for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa) res=(res+cube(calc_hash(ver[i],x)))%mod;
	hash[make_pair(x,fa)]=res;
	return res;
}
inline int calc_hash2(int x,int fa)
{
	if(hash2[make_pair(x,fa)]) return hash2[make_pair(x,fa)];
	int res=Q2;
	for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa) res=(res+cube2(calc_hash2(ver[i],x)))%mod2;
	hash2[make_pair(x,fa)]=res;
	return res;
}
inline int calc_hash3(int x,int fa)
{
	if(hash3[make_pair(x,fa)]) return hash3[make_pair(x,fa)];
	int res=Q3;
	for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa) res=(res+cube3(calc_hash3(ver[i],x)))%mod3;
	hash3[make_pair(x,fa)]=res;
	return res;
}
inline bool calc(int x)
{
	hash[make_pair(0,0)]=hash2[make_pair(0,0)]=0;
	head[0]=0;nxt[++tot]=head[0];ver[tot]=x;head[0]=tot;d[x]++;
	int hhh=calc_hash(0,0),hhh2=calc_hash2(0,0),hhh3=calc_hash3(0,0);
	if(mp[hhh]&&mp2[hhh2]&&mp3[hhh3]) return tot--,d[x]--,0;
	mp[hhh]=mp2[hhh2]=mp3[hhh3]=1;
	return tot--,d[x]--,1;
}
inline void init()
{
	scanf("%I64d",&n);
	for(int i=1,a,b;i<n;i++) scanf("%I64d%I64d",&a,&b),addedge(a,b);
}
signed main()
{
	init();
	int res=0;
	for(int i=1;i<=n;i++) if(d[i]<4&&calc(i)) res++;
	cout<<res;
}

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
typedef long long LL;
const int _=1e2;
const int maxn=1e5+_;

struct node
{
	int x,y,next;
}a[2*maxn];int n,len,last[maxn],du[maxn];
void ins(int x,int y)
{
	len++;
	a[len].x=x;a[len].y=y;
	a[len].next=last[x];last[x]=len;
}

const int hbase=237;
const int hasf=1;
int tot[maxn];LL ha[maxn];
void dfs(int x,int fr)
{
	tot[x]=1; pair<int,LL>t[5];int tlen=0;
	for(int k=last[x];k;k=a[k].next)
	{
		int y=a[k].y;
		if(y!=fr)
		{
			dfs(y,x);
			t[++tlen]=make_pair(tot[y],ha[y]);
			tot[x]+=tot[y];
		}
	}
	sort(t+1,t+tlen+1);
	LL now=hbase;ha[x]=hasf;
	for(int i=1;i<=tlen;i++)
	{
		ha[x]=ha[x]+(LL)t[i].second*now;
		now*=hbase;
	}
	ha[x]=ha[x]*tot[x];
}
int ans;map<int,bool>mp;
void changert(int x,int fr,int hh,int tt)
{
	pair<int,LL>t[5];int tlen=0;
	if(du[x]<4)
	{
		if(tt!=0)t[++tlen]=make_pair(tt,hh);
		t[++tlen]=make_pair(1,hasf);
		for(int k=last[x];k;k=a[k].next)
		{
			int y=a[k].y;
			if(y!=fr)
				t[++tlen]=make_pair(tot[y],ha[y]);
		}
		sort(t+1,t+tlen+1);
		LL now=hbase,hhh=hasf;
		for(int i=1;i<=tlen;i++)
		{
			hhh=hhh+t[i].second*now;
			now*=hbase;
		}
		hhh=hhh*(tot[x]+tt);
		if(mp.find(hhh)==mp.end())mp[hhh]=true,ans++;
	}
	for(int u=last[x];u;u=a[u].next)
	{
		int y=a[u].y;
		if(y!=fr)
		{
			tlen=0;
			if(tt!=0)t[++tlen]=make_pair(tt,hh);
			for(int k=last[x];k;k=a[k].next)
			{
				int yy=a[k].y;
				if(yy!=fr&&yy!=y)
					t[++tlen]=make_pair(tot[yy],ha[yy]);
			}
			sort(t+1,t+tlen+1);
			LL now=hbase,hhh=hasf;
			for(int i=1;i<=tlen;i++)
			{
				hhh=(hhh+t[i].second*now);
				now*=hbase;
			}
			hhh=hhh*(n-tot[y]);
			changert(y,x,hhh,n-tot[y]);
		}
	}
}

int main()
{
	int x,y;
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		ins(x,y),ins(y,x);
		du[x]++,du[y]++;
	}
	dfs(1,0);
	changert(1,0,0,0);
	printf("%d\n",ans);

	return 0;
}

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

#define RG register
#define ll long long
#define For(i, f, t) for (RG int i = f; i <= t; ++i)
#define par(x, a) For (i, 1, x) printf("%d ", a[i]); puts("");

const int N = 111111;

int n, cnt;
int ans[N];
vector<int> e[N];
map<int, int> mp[N];
map<vector<int>, int> H;
set<int> st;

int dp(int x, int fa)
{
	if (mp[x][fa]) return mp[x][fa];
	vector<int> tmp;
	for (int i = 0, _ = e[x].size(); i < _; i++)
		if (e[x][i] != fa) tmp.push_back(dp(e[x][i], x));
	sort(tmp.begin(), tmp.end());
	if (!H[tmp]) H[tmp] = ++cnt;
	return mp[x][fa] = H[tmp];
}

int main()
{
	scanf("%d", &n);
	For (i, 1, n)
	{
		int u, v; scanf("%d %d", &u, &v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	For (i, 1, n)
		if (e[i].size() < 4)
			st.insert(dp(i, 0));
	printf("%d\n", st.size());
	return 0;
}

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

typedef unsigned long long ull;
const int maxn = 1e5+10;
const ull p = 1e8+7;
const ull B = 1e9+7;
ull hs[maxn], hs1[maxn];
int dp[maxn];
int n;

vector<int> G[maxn];

void init()
{
    for(int i = 1; i <= n; ++ i) G[i].clear();
}

void AddEdge(int a, int b)
{
    G[a].push_back(b);
}

int d[maxn];

int getd(int s)
{
    int root = s;
    queue<int> Q;
    Q.push(s);
    memset(d, -1, sizeof(d));
    d[s] = 0;
    while(Q.size())
    {
        int u = Q.front();
        Q.pop();
        if(d[u] > d[root]) root = u;
        for(int i = 0; i < G[u].size(); ++ i)
        {
            int t = G[u][i];
            if(~d[t]) continue;
            else
            {
                d[t] = d[u] + 1;
                Q.push(t);
            }
        }
    }
    return root;
}

int a, b, maxd;

int getmid(int s, int fa, int d)
{
    int dd = d;
    for(int i = 0; i < G[s].size(); ++ i)
    {
        int t = G[s][i];
        if(t == fa) continue;
        int tmp = getmid(t, s, d+1);
        if(d == maxd/2 && tmp == maxd)
        {
            if(maxd&1)
            {
                a = s, b = t;
            }
            else a = s;
        }
        dd = max(dd, tmp);
    }
    return dd;
}

bool cmp(int a, int b)
{
    if(hs[a] != hs[b]) return hs[a] > hs[b];
    return dp[a] > dp[b];
}

void dfs(int s, int fa)
{
    hs[s] = p;
//    hs1[s] = B;
    dp[s] = 0;
    if(G[s].size() < 4) dp[s] ++;
    for(int i = 0; i < G[s].size(); ++ i)
    {
        int t = G[s][i];
        if(t == fa) continue;
        dfs(t, s);
    }
    sort(G[s].begin(), G[s].end(), cmp);
    for(int i = 0; i < G[s].size(); ++ i)
    {
        int t = G[s][i];
        if(t == fa) continue;
        hs[s] = hs[s]*B + hs[t];
//        hs1[s] = hs1[s]*p + hs1[t];
        dp[s] += dp[t];
        for(int j = 0; j < i; ++ j)
        {
            int tt = G[s][j];
            if(tt == fa) continue;
            if(hs[t] == hs[tt] && dp[t] == dp[tt])
            {
                dp[s] -= dp[t];
                break;
            }
        }
    }
}

int main()
{
    while(~scanf("%d", &n))
    {
        init();
        for(int i = 1; i < n; ++ i)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            AddEdge(a, b);
            AddEdge(b, a);
        }
        int rt = getd(1);
        maxd = d[getd(rt)];
        getmid(rt, -1, 0);
        if(maxd&1)
        {
            AddEdge(0, a), AddEdge(0, b);
            rt = 0;
            for(int i = 0; i < G[a].size(); ++ i)
            {
                if(G[a][i] == b) G[a][i] = 0;
            }
            for(int i = 0; i < G[b].size(); ++ i)
            {
                if(G[b][i] == a) G[b][i] = 0;
            }
        }
        else
        {
            rt = a;
        }
        dfs(rt, -1);
        printf("%d\n", dp[rt]-(maxd&1));
    }
    return 0;
}

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_set>
using namespace std;
typedef long long ll;
ll PS[4]={987654323,701123239,812561279,901234531};
ll M=1000000009;

int n;

vector<int> rt[101010];
unordered_set<ll> ls;

ll hshs[101010][5];
bool ihsh[101010][5];

inline int gli(int c, int w){
  if (!w) return 4;
  if (rt[c][0]==w) return 0;
  if (rt[c][1]==w) return 1;
  if (rt[c][2]==w) return 2;
  if (rt[c][3]==w) return 3;
}

vector<ll> hshm[101010];

ll chsh(int c, int p){
  int li=gli(c, p);
  if (ihsh[c][li]) return hshs[c][li];

  hshm[c].clear();
  for (int i=0; i<rt[c].size(); ++i){
    if (i==li) continue;
    hshm[c].push_back(chsh(rt[c][i], c));
  }
  ihsh[c][li]=1;
  hshs[c][li]=1;
  sort(hshm[c].begin(), hshm[c].end());
//   cout << "chsh(" << c << ", " << p << "(" << li << ")) hshm: ";
  for (int i=0; i<hshm[c].size(); ++i){
//     cout << hshm[c][i] << " ";
//     hshs[c][li]+=PS[i]*hshm[c][i];
    hshs[c][li]+=PS[i]*hshm[c][i];
    hshs[c][li]%=M;
  }
  return hshs[c][li];
}

int main(){
  cin >> n;
  for (int i=1; i<n; ++i){
    int a, b;
    cin >> a >> b;
    rt[a].push_back(b);
    rt[b].push_back(a);
  }
//   cout << chsh(1, 0) << endl;
  for (int i=1; i<=n; ++i){
    if (rt[i].size()<4){
      cout << i << ": " << chsh(i, 0) << endl;
      ls.insert(chsh(i, 0));
    }
  }/*
  for (int i=1; i<=n; ++i){
    cout << "#" << i << " ";
    for (int j=0; j<rt[i].size(); ++j) cout << hshs[i][j] << " ";
    cout << endl;
  }*/
  cout << ls.size() << "\n";
}

#include <bits/stdc++.h>
using namespace std;
#define PB push_back
#define ZERO (1e-10)
#define INF (1<<29)
#define CL(A,I) (memset(A,I,sizeof(A)))
#define DEB printf("DEB!\n");
#define D(X) cout<<"  "<<#X": "<<X<<endl;
#define EQ(A,B) (A+ZERO>B&&A-ZERO<B)
typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef vector<ii> vii;
#define IN(n) int n;scanf("%d",&n);
#define FOR(i, m, n) for (int i(m); i < n; i++)
#define REP(i, n) FOR(i, 0, n)
#define F(n) REP(i, n)
#define FF(n) REP(j, n)
#define FT(m, n) FOR(k, m, n)
#define aa first
#define bb second
void ga(int N,int *A){F(N)scanf("%d",A+i);}
#define M1 (1000000007)
#define M2 (1000000009)
#define B1 (257ll)
#define B2 (13ll)
#define MX (100009)
int D[MX],U[MX];
vi g[MX];
void dw(int u,int p,int d,int *D){
    D[u]=d;
    for(auto i:g[u])if(i!=p)
        dw(i,u,d+1,D);
}
ii ctr(int N,int r=0){
    int R,d(0),l(-1);
    dw(r,-1,0,D);
    F(N)if(D[i]>d)d=D[R=i];
    dw(R,-1,d=0,D);
    F(N)if(D[i]>d)d=D[l=i];
    dw(l,-1,0,U);
    d=D[l]>>1;
    if(!(D[l]&1))F(N)if(D[i]==U[i]&&D[i]==d)return {i,-1};
    ii B;
    F(N)if(D[i]==d&&U[i]==d+1)B.bb=i;
    else if(D[i]==d+1&&U[i]==d)B.aa=i;
    return B;
}
unordered_map<int,ii> dp[MX];
ii gh(int u,int p){
    if(dp[u].count(p))return dp[u][p];
    ii W[4],S={0,0};
    int l=0;
    for(auto&h:g[u])if(h^p)W[l++]=gh(h,u);
    sort(W,W+l);
    F(l)S={(S.aa*B1+W[i].aa)%M1,(S.bb*B2+W[i].bb)%M2};
    return dp[u][p]={(S.aa*B1+1)%M1,(S.aa*B2+1)%M2};
}
int dfs(int u,int p){
    set<ii> T;
    int S=g[u].size()<4u;
    for(auto&h:g[u])if(h^p&&!T.count(gh(h,u)))T.insert(gh(h,u)),S+=dfs(h,u);
    return S;
}
int S,N,a,b;
int main(void){
    scanf("%d",&N);
    F(N-1)scanf("%d%d",&a,&b),g[--a].PB(--b),g[b].PB(a);
    ii w=ctr(N);
    S=dfs(w.aa,-1);
    if(~w.bb&&gh(w.aa,-1)==gh(w.bb,-1))S-=dfs(w.bb,w.aa);
    printf("%d\n",S);
    return 0;
}

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
#include<string>
#define LL long long
using namespace std;
const int MAXN = 100005;
const LL MOD1 = 199999LL;
const LL MOD2 = 30319LL;
int n;
int root;
int ans;
vector<int> e[MAXN];
int visited[MAXN];
int size[MAXN];
int weight[MAXN];
int de[MAXN];
int h[MAXN][4];
LL hash[MAXN][4];
int id[2];
inline void init(){
	for(int i = 1; i <= n; i++){
		h[i][0] = (int)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD1;
		h[i][1] = (int)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD1;
		h[i][2] = (int)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD2;
		h[i][3] = (int)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD2;
	}
}
void dfs(int x){
	visited[x] = true;
	size[x] = 1;
	weight[x] = 0;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		if(!visited[y]){
			dfs(y);
			size[x] += size[y];
			weight[x] = max(size[y], weight[x]);
		}
	}
	if(n - size[x] > weight[x]) weight[x] = n - size[x];
}
void add_edge(int x, int y){
	e[x].push_back(y);
	e[y].push_back(x);
	de[x]++; de[y]++;
}
void dfs2(int x, int ht){
	visited[x] = true;
	hash[x][0] = hash[x][1] = 1LL;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		if(!visited[y]){
			dfs2(y, ht + 1);
			hash[x][0] += hash[y][0];
			hash[x][1] += hash[y][1];
			hash[x][2] += hash[y][2];
			hash[x][3] += hash[y][3];
		}
	}
	hash[x][0] = (hash[x][0] * h[ht][0]) % MOD1;
	hash[x][1] = (hash[x][1] * h[ht][1]) % MOD1;
	hash[x][2] = (hash[x][2] * h[ht][2]) % MOD2;
	hash[x][3] = (hash[x][3] * h[ht][3]) % MOD2;
}
void dfs3(int x, int ht){
	int s[4][4], cnt = 0, ok;
	visited[x] = true;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		ok = true;
		if(visited[y])continue;
		for(int j = 0; j < cnt; j++)
		if(hash[y][0] == s[j][0] && hash[y][1] == s[j][1] && hash[y][2] == s[j][2] && hash[y][3] == s[j][3]){
			ok = 0;
			break;
		}
		if(!ok)continue;
		s[cnt][0] = hash[y][0];
		s[cnt][1] = hash[y][1];
		s[cnt][2] = hash[y][2];
		s[cnt][3] = hash[y][3];
		cnt++;
		dfs3(y, ht + 1);
	}
	if(e[x].size() < 4) ans++;
}
int main(){
	srand((int)time(0));
	scanf("%d", &n);
	init();
	for(int i = 1; i < n; i++){
		int x, y;
		scanf("%d%d", &x, &y);
		add_edge(x, y);
	}
	dfs(1);
	for(int i = 1; i <= n; i++){
		if(weight[i] <= n / 2){
			id[1] = id[0];
			id[0] = i;
		}
	}
	if(id[1]){
		ans = -1;
		add_edge(n + 1, id[0]);
		add_edge(n + 1, id[1]);
		vector<int> ::iterator Iter;
		Iter = find(e[id[0]].begin(), e[id[0]].end(), id[1]);
		e[id[0]].erase(Iter);
		Iter = find(e[id[1]].begin(), e[id[1]].end(), id[0]);
		e[id[1]].erase(Iter);
		root = ++n;
	}
	else root = id[0];
	memset(visited, 0, sizeof(visited));
	dfs2(root, 1);
	memset(visited, 0, sizeof(visited));
	dfs3(root, 1);
	printf("%d\n", ans);
	return 0;
}

#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<cstdio>
#include<vector>
#include<cassert>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const double PI=acos(-1);
typedef long long ll;
typedef pair<int,int> pi;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define rep(i,a,b) for (int i=(a);i<=(b);i++)
#define per(i,a,b) for (int i=(a);i>=(b);i--)
#define Rep(i,a,b) for (int i=(a);i<(b);i++)
#define Per(i,a,b) for (int i=(a);i>(b);i--)
//debug
#define deb printf("begin\n");
#define dee printf("end\n");
#define def printf("find\n");
#define dey printf("Yes\n");
#define den printf("No\n");
#define dew printf("wrong\n");
void read(int&x){
	x=0;int f=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if (ch=='-')f=-1,ch=getchar();
	while (ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	x*=f;
}
//--------------------------head--------------------------//

#define maxn 100005
struct Edge{
	int son[maxn<<1],nxt[maxn<<1],lnk[maxn],tot;
	void add(int x,int y){
		tot++;son[tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;
		tot++;son[tot]=x;nxt[tot]=lnk[y];lnk[y]=tot;
	}
	void clear(){
		memset(lnk,0,sizeof(lnk));
		tot=0;
	}
}edge;
int deg[maxn],n;set<int>num;
map<pi,int>f;map<vector<int>,int>hsh;
int dfs(int now,int lst){
	if (f[mp(now,lst)])return f[mp(now,lst)];
	vector<int>hash_son;hash_son.clear();
	for (int j=edge.lnk[now];j;j=edge.nxt[j])
		if (edge.son[j]!=lst)hash_son.pb(dfs(edge.son[j],now));
	sort(hash_son.begin(),hash_son.end());
	//printf("dfs %d %d\n",now,lst);
	//Rep(i,0,hash_son.size())printf("%d ",hash_son[i]);printf("\n");

	return f[mp(now,lst)]=hsh[hash_son]=(hsh[hash_son])?hsh[hash_son]:rand()+1;
}
int main(){
	read(n);
	Rep(i,1,n){
		int x,y;read(x);read(y);
		edge.add(x,y);deg[x]++;deg[y]++;
	}
	rep(i,1,n)if (deg[i]!=4)num.insert(dfs(i,0));
	//rep(i,1,n)printf("%d ",f[mp(i,0)]);printf("\n");
	printf("%d\n",num.size());return 0;
}

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<map>

#define Rep(i,x,y) for (int i=x,_Lim=y;i<=_Lim;i++)
#define Dep(i,x,y) for (int i=x,_Lim=y;i>=_Lim;i--)

#define mk(a,b) make_pair(a,b)

using namespace std;

typedef long long ll;
typedef pair<int,int> PII;

int Stv[1<<8];

inline int read(){
	int f=1,res=0,ch=getchar();
	while (ch<'0' || ch>'9'){
		if (ch=='-') f=-1;ch=getchar();
	}
	while (ch>='0' && ch<='9') res=res*10+ch-48,ch=getchar();
	return f*res;
}
const int N=100005;
const int Mod1=1e9+7;
const int Mod2=1e9+3;

/*
inline bool operator == (PII A,PII B){
	return (A.first==B.first) || (A.second==B.second);
}
inline bool operator != (PII A,PII B){
	return !(A==B);
}
*/

map<pair<int,int>,int>Map;
map<vector<int>,int>Taser;int index;
set<int>Ans;

int lines,front[N];
struct Edge{
	int next,to;
}E[N*2];
inline void Addline(int u,int v){
	E[++lines]=(Edge){front[u],v};front[u]=lines;
}

int Dfs(int u,int fa){
	if (Map.count(make_pair(u,fa))) return Map[make_pair(u,fa)];
	int res1=0,res2=0;
	vector<int> V;V.clear();
	for (int i=front[u],v;i!=0;i=E[i].next){
		if ((v=E[i].to)!=fa){
			V.push_back(Dfs(v,u));
		}
	}
	if (!Taser.count(V))  Taser[V]=++index;
	return Map[make_pair(u,fa)]=Taser[V];
}
int n,Dgr[N];
int main(){
	n=read();
	Rep(i,1,n-1){
		int x=read(),y=read();
		Addline(x,y),Addline(y,x);
		Dgr[x]++,Dgr[y]++;
	}
	Rep(i,1,n) if (Dgr[i]<4){
		Ans.insert(Dfs(i,0));
//		printf("val=%d %d\n",Dfs(i,0).first,Dfs(i,0).second);
	}
	printf("%d\n",Ans.size());
}

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 200005;
const int Q = 1e9 + 7;
int n , pre[N] , mcnt;
struct edge {
    int x , next;
} e[N << 1];

int deg[N];
bool f[N << 1];
int size[N << 1];
int Hash[N << 1];
int power[N * 4];
void addedge(int x , int y) {
    e[mcnt] = (edge) {y , pre[x]} , pre[x] = mcnt ++;
}
int dfs(int o) {
    if (f[o]) {
        return Hash[o];
    } f[o] = 1;
    int x = e[o].x;
    size[o] = 1;
    vector< pair<int , int> > V;
    for (int i = pre[x] ; ~i ; i = e[i].next) {
        int y = e[i].x;
        if ((i ^ o) != 1) {
            V.push_back(make_pair(dfs(i) , i));
            size[o] += size[i];
        }
    }
    sort(V.begin() , V.end());
    Hash[o] = 1;
    for (auto it : V) {
        int y = it.second;
        Hash[o] = ((LL)Hash[o] * power[size[y] * 2] + Hash[y]) % Q;
    }
    Hash[o] = ((LL)Hash[o] * 3 + 2) % Q;
    return Hash[o];
}

int main() {
    power[0] = 1;
    for (int i = 1 ; i < N * 4 ; ++ i) {
        power[i] = (LL)power[i - 1] * 3 % Q;
    }
    scanf("%d" , &n);
    memset(pre , -1,  sizeof(pre));
    for (int i = 0 ; i < n - 1 ; ++ i) {
        int x , y;
        scanf("%d%d" , &x , &y);
        addedge(x , y);
        addedge(y , x);
        ++ deg[x];
        ++ deg[y];
    }
    for (int i = 1 ; i <= n ; ++ i) {
        addedge(i + n , i);
    }
    vector<int> res;
    // for (int i = 0 ; i < mcnt ; ++ i) cout << i << ' ' << dfs(i) << endl;
    set<int> P;
    for (int i = 1 ; i <= n ; ++ i) {
        if (deg[i] + 1 <= 4) {
            int j = n * 2 + i - 3;
            //printf("%d %d\n" , j , e[j].x);
            P.insert(dfs(j));
            //cout << j << ' ' << dfs(j) << endl;
        }
    }
    cout << P.size() << endl;
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>

#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)

using namespace std;

typedef long long LL;
typedef unsigned long long ull;

const int N = 100010;
const int P = 543577;

int n;
struct edge{
	int x,nxt;
}e[N*2];
int h[N],tot;
int r[N];
ull f[N],g[N];
int fa[N];
bool vis[N];
set<ull>s;
int lef[N],rig[N];
ull a[N];
int k;
int siz[N];

void inse(int x,int y){
	e[++tot].x=y;
	e[tot].nxt=h[x];
	h[x]=tot;
}

void calcf(int x){
	vis[x]=1;
	siz[x]=1;
	for(int p=h[x];p;p=e[p].nxt)
	if (!vis[e[p].x]){
		fa[e[p].x]=x;
		calcf(e[p].x);
		siz[x]+=siz[e[p].x];
		rig[e[p].x]=lef[x];
		lef[x]=e[p].x;
	}
	k=0;
	for(int y=lef[x];y;y=rig[y])a[++k]=f[y];
	sort(a+1,a+1+k);
	f[x]=0;
	fo(i,1,k)f[x]=f[x]*P+a[i];
	f[x]=f[x]*P+siz[x];
}

void calcg(int x){
	for(int y=lef[x];y;y=rig[y]){
		a[k=1]=g[x];
		for(int u=lef[x];u;u=rig[u])
		if (u!=y)a[++k]=f[u];
		sort(a+1,a+1+k);
		g[y]=0;
		fo(i,1,k)g[y]=g[y]*P+a[i];
		g[y]=g[y]*P+n-siz[y];
		calcg(y);
	}
}

void calc(){
	int ans=0;
	s.clear();
	fo(x,1,n){
		if (r[x]>=4)continue;
		a[k=1]=1;
		a[++k]=g[x];
		for(int y=lef[x];y;y=rig[y])a[++k]=f[y];
		sort(a+1,a+1+k);
		LL val=0;
		fo(i,1,k)val=val*P+a[i];
		val=val*P+n+1;
		if (s.find(val)==s.end()){
			ans++;
			s.insert(val);
		}
	}
	printf("%d\n",ans);
}

int main(){
	scanf("%d",&n);
	fo(i,2,n){
		int x,y;
		scanf("%d%d",&x,&y);
		inse(x,y);
		inse(y,x);
		r[x]++,r[y]++;
	}
	calcf(1);
	g[1]=0;
	calcg(1);
	calc();
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read(){
	ll x = 0,f = 1;char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();}
	while(ch >= '0' && ch <= '9'){x = x*10+ch-'0';ch = getchar();}
	return x*f;
}

const int N = 100005;
const int mod = 998244353;
const ll seed = 9493101;
const ll M = 1e9+9;
int head[N],nxt[N*2],to[N*2],cnt;
int n;
set<int> s;
map<int,int> f[N];
map<vector<int>,int> mp;
int d[N],tot;

inline void insert(int x,int y){
	to[++cnt] = y; nxt[cnt] = head[x]; head[x] = cnt;
}

inline int dfs(int x,int fa){
	if(f[x][fa]) return f[x][fa];
	vector<int> q;
	for(int i = head[x];i;i = nxt[i])
		if(to[i] != fa)
			q.push_back(dfs(to[i],x));
	sort(q.begin(),q.end());
	if(!mp[q]) mp[q] = ++cnt;
	return f[x][fa] = mp[q];
}

signed main(){
	n = read();
	for(int i = 1;i < n;++i){
		int x = read(),y = read();
		insert(x,y); insert(y,x);
		++d[x]; ++d[y];
	}
	for(int i = 1;i <= n;++i)
		if(d[i] < 4)
			s.insert(dfs(i,0));
	printf("%llu\n", s.size());
	return 0;
}

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
//#include<cmath>
//#include<queue>
//#include<stack>
//#include<map>
#include<set>
using namespace std;
typedef long long ll;
#define x first
#define y second
#define pb push_back
#define mp make_pair
#define all(a) (a).begin(),(a).end()
#define sz(a) ((int)(a).size())
#define vi vector<int>
#define pii pair<int,int>
#define per(i,a,b) for(int i=a;i>=int(b);i--)
#define rep(i,a,b) for(int i=a;i<=int(b);i++)
#define rix(i,x) for(int i=last[x];i;i=pre[i])
ll pow(ll a,ll b,ll M){
	ll t=1;for(a%=M;b;b>>=1){
		if(b&1)t=t*a%M;
		a=a*a%M;
	}
	return t;
}
void R(int&x){
	static char s[22];scanf("%s",s);
	int f=1;char *c=s;x=0;
	if(*c=='-')f=-1,c++;
	for(;*c;c++)x=x*10+*c-'0';
	x*=f;
}

const int N=111111;
vi e[N];int n,s[N],x1,x2,ans,d[N];
int dfs1(int x,int fa){
	s[x]=1;int mx=0;
	for(int y:e[x])if(y!=fa){
		dfs1(y,x);
		s[x]+=s[y];
		mx=max(mx,s[y]);
	}
	mx=max(mx,n-s[x]);
	if(mx<=n/2)if(!x1)x1=x;else x2=x;
}
int f[N],P=1e9+7;
int dfs2(int x,int fa){
	vi a;
	for(int y:e[x])
		if(y!=fa)dfs2(y,x),a.pb(f[y]);
	sort(all(a));
	f[x]=s[x];
	for(int i:a)f[x]=1LL*f[x]*P+i;
}
int dfs3(int x,int fa){
	set<int>q;ans+=d[x]<4;
	for(int y:e[x])if(y!=fa&&!q.count(f[y])){
		dfs3(y,x);
		q.insert(f[y]);
	}
}
int main(){
	cin>>n;
	rep(i,1,n-1){
		int x,y;R(x);R(y);
		e[x].pb(y);e[y].pb(x);
		d[x]++;d[y]++;
	}
	dfs1(1,0);
	dfs2(x1,x2);
	if(x2)dfs2(x2,x1);
	dfs3(x1,x2);
	if(x2&&f[x1]!=f[x2])dfs3(x2,x1);
	cout<<ans<<endl;
}

#include<bits/stdc++.h>

#define pb push_back
#define sz(a) ((int)a.size())
#define x first
#define y second
#define bpt(x) (__builtin_popcount(x))
#define bit(x, y) (((x)>>(y))&1)
#define bclz(x) (__builtin_clz(x))
#define bctz(x) (__builtin_ctz(x))

using namespace std;

using uint = unsigned long long;

typedef double DO;
typedef long long INT;
typedef pair<int, int> pii;
typedef vector<int> VI;

template<typename T, typename U> inline void smin(T &a, U b) {if(a>b) a=b;}
template<typename T, typename U> inline void smax(T &a, U b) {if(a<b) a=b;}

template<class T>inline void gn(T &x) {char c, sg=0; while (c=getchar(), (c>'9' || c<'0') && c!='-');for((c=='-'?sg=1, c=getchar():0), x=0; c>='0' && c<='9'; c=getchar()) x=(x<<1)+(x<<3)+c-'0';if (sg) x=-x;}
template<class T>inline void print(T x) {if (x<0) {putchar('-');return print(-x);}if (x<10) {putchar('0'+x);return;} print(x/10);putchar(x%10+'0');}
template <class T> inline void println(T x) {print(x); putchar('\n');}

int power(int a, int b, int m, int ans=1) {
	for(; b; b>>=1, a=1LL*a*a%m) if(b&1) ans=1LL*ans*a%m;
	return ans;
}

#define NN 100111
const int hmod = 100102021;
VI adj[NN];
uint val[NN];
uint jia[NN];
uint up[NN];
int n;
int son[NN];
vector<uint> vec[NN];
int nn;
int p[NN];

void dfs(int u, int fa=0) {
	son[u]=1;
	p[u] = fa;
	for(int v : adj[u]) {
		if(v == fa) continue;
		dfs(v, u);
		son[u]+=son[v];
		vec[u].pb(val[v]);
	}
	vec[u].pb(son[u]);
	vec[u].pb(sz(adj[u]));
	sort(vec[u].begin(), vec[u].end());
	for(uint &v : vec[u]) {
		val[u]=val[u]*hmod+v;
	}
}

set<uint> s;
void rdfs(int u, int fa=0) {
	if(fa) {
		vec[u].clear();
		for(int v : adj[fa]) if(v != p[fa] and v != u) {
			vec[u].pb(val[v]);
		}
		if(p[fa]) vec[u].pb(up[p[fa]]);
		vec[u].pb(sz(adj[fa]));
		vec[u].pb(n-son[u]);
		sort(vec[u].begin(), vec[u].end());

		up[fa]=0;
		for(uint &v : vec[u]) {
			up[fa]=up[fa]*hmod+v;
		}
		vec[u].clear();
		for(int v : adj[u]) {
			if(v==fa) vec[u].pb(up[fa]);
			else vec[u].pb(val[v]);
		}
		vec[u].pb(sz(adj[u]));
		vec[u].pb(n);
		sort(vec[u].begin(), vec[u].end());
		jia[u]=0;
		for(uint &v : vec[u]) {
			jia[u]=jia[u]*hmod+v;
		}

	} else jia[u]=val[u];
	if(sz(adj[u])<4) s.insert(jia[u]);
	for(int v : adj[u]) if(v!=fa) {
		rdfs(v, u);
	}

}
int solve() {
	cin >> n;
	for(int i=0; i<n-1; i++) {
		int u, v; gn(u); gn(v);
		adj[u].pb(v); adj[v].pb(u);
	}
	int root;
	srand(time(0));
	root=rand()%n+1;
	dfs(root);
	rdfs(root);
	cout << sz(s) << endl;
}

int main() {
#ifndef	ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	solve();
	return 0;
}

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>

using namespace std;

#define mp make_pair
#define pb push_back
#define ll long long

#define maxN 100011
#define mod 1000000007
#define base 31

int n, i, x, y;
vector<int> list[maxN];
ll dp[maxN];
vector<ll> sol;

ll compute(int node, int deny) {
    static ll ans;
    static vector<int> aux;

    aux.clear();

    for (auto to : list[node])
        if (deny != to)
            aux.pb(dp[to]);

    ans = 1;
    sort(aux.begin(), aux.end());
    reverse(aux.begin(), aux.end());

    for (auto e : aux)
        ans = (ans * base + e) % mod;

    ans = (ans * base + aux.size() * 1311) % mod;

    return ans;
}

void dfs(int node, int root) {

    for (auto to : list[node])
        if (to != root)
            dfs(to, node);

    dp[node] = compute(node, root);
}

void solve(int node, int root) {
    if (list[node].size() < 4)
        sol.pb(compute(node, 0));

    for (auto to : list[node]) {
        if (to == root) continue;
        dp[node] = compute(node, to);
        solve(to, node);
    }

    dp[node] = compute(node, root);
}

int main()
{
    //freopen("test.in","r",stdin);

    scanf("%d", &n);
    for (i = 1; i < n; i++) {
        scanf("%d%d", &x, &y);
        list[x].pb(y);
        list[y].pb(x);
    }

    dfs(1, 0);
    solve(1, 0);

    sort(sol.begin(), sol.end());
    sol.resize(unique(sol.begin(), sol.end()) - sol.begin());

    printf("%d\n", sol.size());

    return 0;
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>

#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)

using namespace std;

typedef long long LL;
typedef unsigned long long ull;

const int N = 100010;
const int P = 543577;

int n;
struct edge{
	int x,nxt;
}e[N*2];
int h[N],tot;
int r[N];
ull f[N],g[N];
int fa[N];
bool vis[N];
set<ull>s;
int lef[N],rig[N];
ull a[N];
int k;
int siz[N];

void inse(int x,int y){
	e[++tot].x=y;
	e[tot].nxt=h[x];
	h[x]=tot;
}

void calcf(int x){
	vis[x]=1;
	siz[x]=1;
	for(int p=h[x];p;p=e[p].nxt)
	if (!vis[e[p].x]){
		fa[e[p].x]=x;
		calcf(e[p].x);
		siz[x]+=siz[e[p].x];
		rig[e[p].x]=lef[x];
		lef[x]=e[p].x;
	}
	k=0;
	for(int y=lef[x];y;y=rig[y])a[++k]=f[y];
	sort(a+1,a+1+k);
	f[x]=0;
	fo(i,1,k)f[x]=f[x]*P+a[i]+1;
	f[x]=f[x]*P+siz[x];
}

void calcg(int x){
	for(int y=lef[x];y;y=rig[y]){
		a[k=1]=g[x];
		for(int u=lef[x];u;u=rig[u])
		if (u!=y)a[++k]=f[u];
		sort(a+1,a+1+k);
		g[y]=0;
		fo(i,1,k)g[y]=g[y]*P+a[i]+1;
		g[y]=g[y]*P+n-siz[y];
		calcg(y);
	}
}

void calc(){
	int ans=0;
	s.clear();
	fo(x,1,n){
		if (r[x]>=4)continue;
		a[k=1]=1;
		a[++k]=g[x];
		for(int y=lef[x];y;y=rig[y])a[++k]=f[y];
		sort(a+1,a+1+k);
		LL val=0;
		fo(i,1,k)val=val*P+a[i]+1;
		val=val*P+n+1;
		if (s.find(val)==s.end()){
			ans++;
			s.insert(val);
		}
	}
	printf("%d\n",ans);
}

int main(){\
	scanf("%d",&n);
	fo(i,2,n){
		int x,y;
		scanf("%d%d",&x,&y);
		inse(x,y);
		inse(y,x);
		r[x]++,r[y]++;
	}
	calcf(1);
	g[1]=0;
	calcg(1);
	calc();
	return 0;
}

#include <iostream>
#include <vector>
#include <array>
#include <stdio.h>
#include <ios>
#include <string.h>
#include <algorithm>
#include <functional>

constexpr unsigned primes[]{ 2672090437, 2569161337, 2414657393 };
constexpr int np = sizeof(primes) / sizeof(*primes);

std::vector<std::array<unsigned, np> > pow2;
void setpow2(int maxp) {
	pow2.resize(maxp + 1);
	for (int i = 0; i < np; i++)
		pow2[0][i] = 1;
	for (int i = 1; i <= maxp; i++)
		for (int j = 0; j < np; j++)
			pow2[i][j] = pow2[i - 1][j] * 2ULL % primes[j];
}

struct hash {
	unsigned m[np];
	int nbits;
	hash() {}
	hash(unsigned num, int nbits = 1) : nbits(nbits) {
		for (int i = 0; i < np; i++)
			m[i] = num;
	}
};
hash join(hash a, hash b) {
	hash out;
	out.nbits = a.nbits + b.nbits;
	for (int i = 0; i < np; i++)
		out.m[i] = (a.m[i] * (uint64_t)pow2[b.nbits][i]  + b.m[i]) % primes[i];
	return out;
}
bool operator<(hash a, hash b) {
	if (a.nbits != b.nbits)
		return a.nbits == b.nbits;
	return memcmp(a.m, b.m, sizeof(a.m)) < 0;
}

#define N 100000
int w[N];
std::vector<int> adj[N];
hash h0[N];
hash hnew[N];
int deg[N];

int findw(int v, int par = -1) {
	int t = 1;
	for (int x : adj[v]) {
		if (x != par)
			t += findw(x, v);
	}
	return w[v] = t;
}

void genh0(int v, bool rec = true) {
	std::vector<hash> hch;
	for (int x : adj[v]) {
		if(rec)
			genh0(x);
		hch.push_back(h0[x]);
	}
	std::sort(hch.begin(), hch.end());
	hash out(0);
	for (const auto& h : hch)
		out = join(out, h);
	h0[v] = join(out, hash(1));
}

void hconcat(int v, hash h) {
	hnew[v] = memcmp(hnew[v].m, h.m, sizeof(h.m)) < 0 ?
		join(hnew[v], h) : join(h, hnew[v]);
	for (int x : adj[v])
		hconcat(x, h);
}

int main()
{
	std::ios_base::sync_with_stdio(false);
	int n;
	scanf("%d", &n);
	setpow2(2 * n + 5);
	for (int i = n; --i; ) {
		int a, b;
		scanf("%d %d", &a, &b);
		--a; --b;
		adj[a].push_back(b);
		adj[b].push_back(a);
		++deg[a];
		++deg[b];
	}
	findw(0);
	std::vector<int> center;
	for (int i = n; i--;) {
		if (n % 2 == 0 && w[i] == n / 2) {
			for (int j : adj[i]) {
				if (w[j] > w[i]) {
					center = { i, j };
					break;
				}
			}
			break;
		}
		else if (n - w[i] < (n + 1) / 2) {
			bool isC = true;
			for (int v : adj[i])
				isC &= w[v] > w[i] || w[v] < (n + 1) / 2;
			if (isC) {
				center = { i };
				break;
			}
		}
	}
	bool ecent = center.size() == 2;
	for (auto i = center.size(); i--; )
		findw(center[i], center[i ^ ecent]);

	for (int i = n; i--;) {
		std::sort(adj[i].begin(), adj[i].end(), [](int a, int b) {
			return w[a] < w[b];
		});
		if (n > 1 && (ecent || i != center[0]))
			adj[i].pop_back();
	}

	struct split {
		const int* eqb, *eqe;
		hash pre, post;
	};
	std::vector<split> ss;
	const hash h01 = join(hash(0), hash(1));
	std::function<void(int, hash, hash, int)> genh;
	int nbad = 0;
	genh = [&](int v, hash pre, hash post, int skipw) {
		if (deg[v] < 4) {
			hash h = join(pre, h01);
			for (int x : adj[v])
				h = join(h, h0[x]);
			h = join(h, post);

			for (auto it = ss.crbegin(); it != ss.crend(); ++it) {
				hash hh = it->pre;
				bool inserted = false;
				for (const int* i = it->eqb; i != it->eqe; ++i) {
					if (!inserted && memcmp(h.m, h0[*i].m, sizeof(h.m)) < 0) {
						inserted = true;
						hh = join(hh, h);
					}
				}
				if (!inserted)
					hh = join(hh, h);
				h = join(hh, it->post);
			}
			hnew[v] = h;
		} else {
			nbad++;
		}

		for (auto aj = adj[v].cbegin(), ae = adj[v].cend(); aj != ae; ++aj) {
			if (w[*aj] == skipw)
				continue;
			auto a2 = aj;
			do ++a2; while (a2 != ae && w[*a2] == w[*aj]);
			hash pre2 = pre, post2 = post;
			for (auto a = adj[v].cbegin(); a != a2; ++a) {
				if (a != aj)
					pre2 = join(pre2, h0[*a]);
			}
			if (a2 != ae && w[*a2] == w[*aj] + 1) {
				auto a3 = a2;
				do ++a3; while (a3 != ae && w[*a3] == w[*a2]);
				for (auto a = ae; a != a3; )
					post2 = join(h0[*--a], post2);
				ss.push_back(split{ &*a2, &*a3, pre2, post2 });
				genh(*aj, hash(0), hash(1), -1);
				ss.pop_back();
			} else {
				for (auto a = ae; a != a2; )
					post2 = join(h0[*--a], post2);
				pre2 = join(pre2, hash(0));
				post2 = join(hash(1), post2);
				genh(*aj, pre2, post2, -1);
			}

		}
	};
	if (ecent) {
		genh0(center[0]);
		genh0(center[1]);
		for (int i : {0, 1}) {
			int c = center[i];
			adj[c].push_back(center[i ^ 1]);
			genh(c, hash(0, 0), hash(0, 0), n / 2);
			adj[c].pop_back();
		}
	} else {
		int c = center[0];
		genh0(c);
		genh(c, hash(0, 0), hash(0, 0), n / 2);
		for (auto i = adj[c].size(); i--; ) {
			int c2 = adj[c][i];
			adj[c].erase(adj[c].begin() + i);
			genh0(c, false);
			genh(c2, hash(0, 0), hash(0, 0), -1);
			adj[c].insert(adj[c].begin() + i, c2);
			hconcat(c2, h0[c]);
		}
	}
	std::sort(hnew, hnew + n);
	int ans = 1;
	for (int i = nbad + 1; i < n; i++) {
		if (memcmp(hnew + i, hnew + i - 1, sizeof(*hnew)))
			++ans;
	}
	std::cout << ans;

    return 0;
}

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
#define MP make_pair
#define F first
#define S second
using namespace std;
typedef long long ll;
ll A=1000000007;
ll M=1122000013;

ll B=701123239;
ll M2=987654323;

int n;

vector<int> rt[101010];

unordered_set<ll> ls;

ll hshs[101010][5];
ll hshis[101010][5];
bool ihsh[101010][5];

unordered_map<ll, ll> hshi;
ll hshindex;

ll ghshi(ll hsh){
  if (hshi.count(hsh)) return hshi[hsh];
  hshi[hsh]=(hshindex+B)%M2;
  return hshindex;
}

inline int gli(int c, int w){
  if (!w) return 4;
  if (rt[c][0]==w) return 0;
  if (rt[c][1]==w) return 1;
  if (rt[c][2]==w) return 2;
  if (rt[c][3]==w) return 3;
}

vector<ll> hshm;

ll chsh(int c, int p){
  int li=gli(c, p);
  if (ihsh[c][li]) return hshis[c][li];

  for (int i=0; i<rt[c].size(); ++i){
    if (i==li) continue;
    chsh(rt[c][i], c);
  }
  hshm.clear();
  for (int i=0; i<rt[c].size(); ++i){
    if (i==li) continue;
    hshm.push_back(chsh(rt[c][i], c));
  }
  ihsh[c][li]=1;
  sort(hshm.begin(), hshm.end());
  hshs[c][li]=1;
  for (int i=0; i<hshm.size(); ++i){
    hshs[c][li]+=hshm[i];
    hshs[c][li]*=A;
    hshs[c][li]%=M;
  }
  hshis[c][li]=ghshi(hshs[c][li]);
  return hshis[c][li];
}

int main(){
  cin >> n;
  for (int i=1; i<n; ++i){
    int a, b;
    cin >> a >> b;
    rt[a].push_back(b);
    rt[b].push_back(a);
  }

  for (int i=1; i<=n; ++i){
    if (rt[i].size()<4){
      ls.insert(chsh(i, 0));
    }
  }

  cout << ls.size() << "\n";
}

#include <cstdio>
#include <algorithm>
#include <cstdlib>
const long long MOD = 1234321237;
int head[100001], next[199999], to[199999], N, E, q[100001], fa[100001], D;
long long ROOT[100001], SUB[100001], UP[100001], vec[100000], ran[100000], tail[100000];
std::pair < long long, int > Z[100001];
int main()
{
	scanf("%d", &N);
	srand(55011177);
	for (int i = 0; i < N; i++)
		ran[i] = rand() % MOD;
	for (int i = 1, u, v; i < N; i++)
	{
		scanf("%d%d", &u, &v);
		next[++E] = head[u], to[E] = v, head[u] = E;
		next[++E] = head[v], to[E] = u, head[v] = E;
	}
	int *H = q, *T = q + 1;
	*T = 1;
	while (H < T)
		for (int u = *++H, e = head[u]; e; e = next[e])
			if (to[e] != fa[u])
				fa[*++T = to[e]] = u;
	for (int i = N, u = q[i]; i; u = q[--i])
	{
		D = 0;
		for (int e = head[u]; e; e = next[e])
			if (to[e] != fa[u])
				vec[D++] = SUB[to[e]];
		std::sort(vec, vec + D);
		for (int j = 0; j < D; j++)
			SUB[u] = (SUB[u] + vec[j] * ran[j]) % MOD;
		SUB[u] = (SUB[u] + ran[D] * ran[D]) % MOD;
	}
	for (int i = 1, u = q[i]; i <= N; u = q[++i])
	{
		if (u != 1)
		{
			Z[0] = { UP[u], fa[u] };
			D = 1;
		}
		else
			D = 0;
		for (int e = head[u]; e; e = next[e])
			if (to[e] != fa[u])
				Z[D++] = { SUB[to[e]], to[e] };
		std::sort(Z, Z + D);
		tail[D] = 0;
		for (int j = D - 1; j; j--)
			tail[j] = (tail[j + 1] + Z[j].first * ran[j - 1]) % MOD;
		long long S = 0;
		for (int j = 0; j < D; j++)
		{
			long long U = (S + tail[j + 1] + ran[D - 1] * ran[D - 1]) % MOD;
			if (Z[j].second != fa[u])
				UP[Z[j].second] = U;
			S = (S + Z[j].first * ran[j]) % MOD;
		}
	}
	for (int i = 1; i <= N; i++)
	{
		D = 0;
		for (int e = head[i]; e; e = next[e])
			vec[D++] = to[e] == fa[i] ? UP[i] : SUB[to[e]];
		std::sort(vec, vec + D);
		for (int j = 0; j < D; j++)
			ROOT[i] = (ROOT[i] + vec[j] * ran[j]) % MOD;
		ROOT[i] = (ROOT[i] + ran[D] * ran[D]) % MOD;
	}
	D = 0;
	for (int i = 1; i <= N; i++)
		if (!next[next[next[head[i]]]])
			vec[D++] = ROOT[i];
	std::sort(vec, vec + D);
	D = std::unique(vec, vec + D) - vec;
	printf("%d\n", D);
	return 0;
}

#include <iostream>
#include <fstream>
#include <vector>
#include <stack>
#include <queue>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <map>
#include <set>

using namespace std;

typedef long long ll;
typedef pair<int,int> PP;

/*
    freopen("input","r",stdin);
    freopen("output","w",stdout);
*/

vector<vector<int> > G;

map<pair<int, int>, ll> H;

ll MOD = 1E9 + 7;
ll M = 1E7 + 7;
ll P = 1E7 + 3;

ll cal(int x, int p) {
	pair<int, int> r;
	r.first = x;
	r.second = p;
	if (H.find(r) != H.end()) return H[r];
	vector<ll> num;
	for (int i = 0;i < G[x].size();i++) {
		int j = G[x][i];
		if (j == p) continue;
		num.push_back(cal(j, x));
	}
	ll crt = P;
	ll ans = 1;
	ll t = M;
	sort(num.begin(), num.end());
	for (int i = 0;i < num.size();i++) {
		crt += (num[i] % MOD) * t;
		if (i != num.size() - 1) crt %= MOD;
		t *= M;
		t %= MOD;
		ans *= num[i];
		ans %= MOD;
	}
	crt += ans;
	crt %= MOD;
	H[r] = crt;
	return crt;
}

int main() {
    ios::sync_with_stdio(false);
    int n;
    scanf("%d", &n);
    G.resize(n + 1);
    for (int i = 1;i < n;i++) {
    	int a, b;
    	scanf("%d%d", &a, &b);
    	G[a].push_back(b);
    	G[b].push_back(a);
    }
    unordered_set<ll> R;
    for (int i = 1;i <= n;i++) {
    	if (G[i].size() == 4) continue;
    	ll ans = cal(i, 0);
    	R.insert(ans);
    }
    cout << R.size() << endl;
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define lp(i,l,r)for(auto i=l;i<=r;++i)
#define rp(i,r,l)for(auto i=r;i>=l;--i)

#include<bits/stdc++.h>
using namespace std;
struct TreeHashing{
	int n,p;
	vector<int>hu,hd,hash,sz;
	vector<long long>pw;
	vector<vector<int>>adj;
	TreeHashing(int _n,int _p=1e9+7):
		n(_n),pw(2*n),hu(n+1),hd(n+1),
		sz(n+1,1),adj(n+1),hash(n+1),p(_p){}
	void add(int u,int v){
		adj[u].push_back(v);
		adj[v].push_back(u);
	}
	void down(int u,int d=0,int f=0){
		vector<pair<int,int>>t;
		for(int v:adj[u])
			if(v!=f){
				down(v,d,u);
				sz[u]+=sz[v]*(1-d);
				t.push_back(make_pair(sz[v]*2,hd[v]));
			}
		if(d*f)
			t.push_back(make_pair((n-sz[u])*2,hu[u]));
		sort(t.begin(),t.end());
		int l=1,&s=d?hash[u]:hd[u];
		for(auto i:t){
			s=(s+pw[l]*i.second)%p;
			l+=i.first;
		}
		s=(s+pw[l])%p;
	}
	void up(int u,int f=0){
		int l=0,sl=0,sr=1;
		vector<pair<pair<int,int>,int>>t;
		if(f)
			t.push_back(make_pair(make_pair((n-sz[u])*2,hu[u]),0));
		for(int i=0;i<adj[u].size();++i)
			if(adj[u][i]!=f){
				int v=adj[u][i];
				t.push_back(make_pair(make_pair(sz[v]*2,hd[v]),v));
			}
		sort(t.begin(),t.end());
		for(auto i:t){
			sl=(sl+i.first.second*pw[l])%p;
			l+=i.first.first;
		}
		for(int i=int(t.size()-1);i>=0;--i){
			sl=(sl-t[i].first.second*pw[l-=t[i].first.first]+p)%p;
			if(i+1<t.size())
				sr=(sr*pw[t[i+1].first.first]+t[i+1].first.second)%p;
			if(t[i].second)
				hu[t[i].second]=(sl+sr*pw[l])*2%p;
		}
		for(int v:adj[u])
			if(v!=f)
				up(v,u);
	}
	void run(){
		pw[0]=1;
		for(int i=1;i<2*n;++i)
			pw[i]=pw[i-1]*2%p;
		down(1),up(1),down(1,1);
	}
};
int main(){
	ios::sync_with_stdio(0);
	int n;cin>>n;
	TreeHashing th(n);
	vector<int>d(n+1);
	lp(i,1,n-1){
		int u,v;
		cin>>u>>v;
		++d[u],++d[v];
		th.add(u,v);
	}
	th.run();
	set<int>s;
	lp(i,1,n)if(d[i]<4)s.insert(th.hash[i]);
	cout<<s.size()<<endl;
	#ifndef ONLINE_JUDGE
	for(;;);
	#endif
	return 0;
}

#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;

const int maxn = 2e5 + 10;
typedef unsigned long long ull;
typedef int arr[maxn<<2];
typedef ull prr[maxn<<2];
typedef pair<ull, int> pii;
const ull base = 4000037, mod = 1e9 + 7;

int edg, vsz, n;
prr sha, pmd = {1}, vec;
arr vedg, frm, to, nxt, last, deg, sz;

inline void add_mod(ull &x, ull y, ull z) {
	x += (y * z) % mod;
	if (x > mod) x -= mod;
}
void add_edge(int u, int v) {
	frm[++edg] = u, to[edg] = v, nxt[edg] = last[u], last[u] = edg;
	frm[++edg] = v, to[edg] = u, nxt[edg] = last[v], last[v] = edg;
	deg[u]++, deg[v]++;
}

void dfs(int x) {
	vedg[x] = 1;
	pii px[6] = {};
	int psz = 0;
	for (int i = last[to[x]]; i; i = nxt[i])
		if (to[i] != frm[x]) {
			if (!vedg[i]) dfs(i);
			px[++psz] = pii(sha[i], sz[i]);
			sz[x] += sz[i];
		}
	sort(px+1, px+psz+1);
	for (int i = 1; i <= psz; ++i)
		add_mod(sha[x], px[i].fi, pmd[px[i].se+1]);
	sha[x]++;
	sz[x]++;
}
int main() {
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	ios::sync_with_stdio(0);

	cin >> n;
	for (int i = 1; i <= n+1; ++i) add_mod(pmd[i], pmd[i-1], base);

	for (int i = 1, u, v; i < n; ++i)
		cin >> u >> v, add_edge(u, v);

	for (int i = 1; i <= edg; ++i)
		if (!vedg[i])
			dfs(i);

	for (int x = 1; x <= n; ++x)
		if (deg[x] <= 3) {
			pii px[6];
			int psz = 0;
			ull psha = 0;
			for (int i = last[x]; i; i = nxt[i])
				px[++psz] = pii(sha[i], sz[i]);
			sort(px+1, px+psz+1);
			for (int i = 1; i <= psz; ++i)
				add_mod(psha, px[i].fi, px[i].se);
			vec[++vsz] = psha;
		}

	sort(vec+1, vec+vsz+1);
	cout << (unique(vec+1, vec+vsz+1) - vec - 1);
}

#include<bits/stdc++.h>
#define mii map<int,int>
using namespace std;
int n, cnt, u, v, deg[101000];
map<mii,int>mp;
mii f[101000], ans, G[101000];

int dfs(int x,int fff){
  if (f[x].count(fff)) return f[x][fff];
  mii v;
  for (auto y:G[x])
    if (y.first!=fff)
      v[dfs(y.first,x)];
  if (!mp.count(v)) mp[v]=++cnt;
  return f[x][fff]=mp[v];
}

int main(){
  cin>>n;
  for (int i=n;--i;){
    cin>>u>>v; ++deg[u],++deg[v];
    G[u][v],G[v][u];
  }
  for (int i=1;i<=n;++i)
    if (deg[i]<4)
      ans[dfs(i,0)]=1;
  cout<<ans.size();
}

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_set>
using namespace std;
typedef long long ll;
ll PS[4]={987654323,701123239,812561279,901234531};
ll M=1122000013;

int n;

vector<int> rt[101010];
unordered_set<ll> ls;

ll hshs[101010][5];
bool ihsh[101010][5];

inline int gli(int c, int w){
  if (!w) return 4;
  if (rt[c][0]==w) return 0;
  if (rt[c][1]==w) return 1;
  if (rt[c][2]==w) return 2;
  if (rt[c][3]==w) return 3;
}

vector<ll> hshm[101010];

ll chsh(int c, int p){
  int li=gli(c, p);
  if (ihsh[c][li]) return hshs[c][li];

  hshm[c].clear();
  for (int i=0; i<rt[c].size(); ++i){
    if (i==li) continue;
    hshm[c].push_back(chsh(rt[c][i], c));
  }
  ihsh[c][li]=1;
  hshs[c][li]=1;
  sort(hshm[c].begin(), hshm[c].end());
//   cout << "chsh(" << c << ", " << p << "(" << li << ")) hshm: ";
  for (int i=0; i<hshm[c].size(); ++i){
//     cout << hshm[c][i] << " ";
    hshs[c][li]+=PS[i]*hshm[c][i];
    hshs[c][li]%=M;
  }
  return hshs[c][li];
}

int main(){
  cin >> n;
  for (int i=1; i<n; ++i){
    int a, b;
    cin >> a >> b;
    rt[a].push_back(b);
    rt[b].push_back(a);
  }
  for (int i=1; i<=n; ++i){
    if (rt[i].size()<4) ls.insert(chsh(i, 0));
  }/*
  for (int i=1; i<=n; ++i){
    cout << "#" << i << " ";
    for (int j=0; j<rt[i].size(); ++j) cout << hshs[i][j] << " ";
    cout << endl;
  }*/
  cout << ls.size() << "\n";
}

/* Author haleyk10198 */
/* �@��:  haleyk10198 */
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#define MOD 1000000007
#define LINF (1LL<<60)
#define INF 2147483647
#define PI 3.1415926535897932384626433
#define ll long long
#define pii pair<int,int>
#define mp(x,y) make_pair((x),(y))

using namespace std;
using namespace __gnu_pbds;

map<vector<int>, int> m1;

vector<int> near[100010];
vector<int> hh[100010];
int n;
set<int> res;

void dfs(int now,int p){
	for(int x:near[now])
		if(x-p){
			dfs(x,now);
			hh[now].push_back(m1[hh[x]]);
		}
	while(hh[now].size()<4)
		hh[now].push_back(-1);
	sort(hh[now].begin(),hh[now].end());
	if(!m1.count(hh[now]))
		m1[hh[now]]=m1.size();
}

void move(int u,int v){
	hh[u].erase(find(hh[u].begin(),hh[u].end(),m1[hh[v]]));
	hh[u].push_back(-1);
	sort(hh[u].begin(),hh[u].end());
	if(!m1.count(hh[u]))
		m1[hh[u]]=m1.size();
	hh[v].erase(find(hh[v].begin(),hh[v].end(),-1));
	hh[v].push_back(m1[hh[u]]);
	sort(hh[v].begin(),hh[v].end());
	if(!m1.count(hh[v]));
		m1[hh[v]]=m1.size();
}

void solve(int now,int p){
	if(near[now].size()!=4)
		res.insert(m1[hh[now]]);
	for(int x:near[now])
		if(x-p){
			move(now,x);
			solve(x,now);
			move(x,now);
		}
}

int main(){
	//freopen("input.txt","r",stdin);
	//freopen("output.txt","w",stdout);
	ios_base::sync_with_stdio(false);
	cin>>n;
	for(int i=1,u,v;i<n;i++){
		cin>>u>>v;
		--u,--v;
		near[u].push_back(v);
		near[v].push_back(u);
	}
	dfs(0,0);
	solve(0,0);
	cout<<res.size()<<endl;
	return 0;
}

#include<bits/stdc++.h>
#define sqr(x) ((x)*(x))
#define ll long long
#define ull unsigned long long
#define ui unsigned int
#define ld long double
#define vi vector<int>
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define debuge cerr<<"isok"<<endl
#define debug(x) cerr<<#x<<"="<<x<<endl
#define SS second
#define FF first
#define ls (k<<1)
#define rs (k<<1|1)
#define inf 0x3f3f3f3f
#define clr(a,x) memset(a,x,sizeof(a))
using namespace std;

const int N=100005,M=100005,m1=998244353,m2=1e9+9,base=1e6+3;
inline void gmin(int &x,int y){if(x>y) x=y;}
inline void gmax(int &x,int y){if(x<y) x=y;}

struct node{int to,next;}p[N<<2];
int n,tot,head[N],du[N];
set<ull> s;
map<int,ull> dp[N];
void add(int x,int y){
	p[++tot]=(node){y,head[x]};head[x]=tot;
	p[++tot]=(node){x,head[y]};head[y]=tot;
}
ull f1(ull x){
	return x*x*x*3+x*5+103751981;
}
ull dfs(int x,int f){
	if(dp[x].count(f)) return dp[x][f];
	ull &ans=dp[x][f];ans=1;
	for(int i=head[x];i;i=p[i].next){
		int y=p[i].to;
		if(y==f) continue;
		ans*=dfs(y,x);
	}
	ull t=f1(du[x]);
	ans-=t;
	ans^=t;
	return ans;
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);du[x]++;du[y]++;
	}
	for(int i=1;i<=n;i++) if(du[i]<4) s.insert(dfs(i,0));
	printf("%d\n",(int)s.size());
	return 0;
}

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_set>
using namespace std;
typedef long long ll;
ll PS[4]={987654323,701123239,812561279,901234531};
ll M=1122000013;

int n;

vector<int> rt[101010];
unordered_set<ll> ls;

ll hshs[101010][5];
bool ihsh[101010][5];

inline int gli(int c, int w){
  if (!w) return 4;
  if (rt[c][0]==w) return 0;
  if (rt[c][1]==w) return 1;
  if (rt[c][2]==w) return 2;
  if (rt[c][3]==w) return 3;
}

vector<ll> hshm[101010];

ll chsh(int c, int p){
  int li=gli(c, p);
  if (ihsh[c][li]) return hshs[c][li];

  hshm[c].clear();
  for (int i=0; i<rt[c].size(); ++i){
    if (i==li) continue;
    hshm[c].push_back(chsh(rt[c][i], c));
  }
  ihsh[c][li]=1;
  sort(hshm[c].begin(), hshm[c].end());
//   cout << "chsh(" << c << ", " << p << "(" << li << ")) hshm: ";
  for (int i=0; i<hshm[c].size(); ++i){
//     cout << hshm[c][i] << " ";
//     hshs[c][li]+=PS[i]*hshm[c][i];
    hshs[c][li]+=hshm[c][i];
    hshs[c][li]*=PS[i];
    hshs[c][li]%=M;
  }
  hshs[c][li]+=1;
  return hshs[c][li];
}

int main(){
  cin >> n;
  for (int i=1; i<n; ++i){
    int a, b;
    cin >> a >> b;
    rt[a].push_back(b);
    rt[b].push_back(a);
  }
//   cout << chsh(1, 0) << endl;
  for (int i=1; i<=n; ++i){
    if (rt[i].size()<4){
//       cout << i << ": " << chsh(i, 0) << endl;
      ls.insert(chsh(i, 0));
    }
  }/*
  for (int i=1; i<=n; ++i){
    cout << "#" << i << " ";
    for (int j=0; j<rt[i].size(); ++j) cout << hshs[i][j] << " ";
    cout << endl;
  }*/
  cout << ls.size() << "\n";
}

#include <bits/stdc++.h>
#define forinc(i,a,b) for(int i = a, _key = b; i <= _key; ++i)
#define fordec(i,a,b) for(int i = a, _key = b; i >= _key; --i)
#define fori(i,n) for(int i = 0, _key = n; i < _key; ++i)
#define ford(i,n) for(int i = n - 1; i >= 0; --i)
#define forvct(i,v) for(int i = 0, _key = v.size(); i < _key; ++i)
#define sqr(x) ((ll)x) * (x)
#define task "x"
#define st first
#define nd second
#define m_p make_pair
#define m_t make_tuple
#define p_b push_back
#define p_f push_front
#define pp_b pop_back
#define pp_f pop_front
#define sn string::npos
#define heap priority_queue
#define ll long long
#define db double
#define str string
#define nn 100010

using namespace std;

const int oo = 1000000007;

int n, res, f[nn], g[nn];
vector<int> adj[nn];
vector<pair<int,int> > a[nn];
map<int,bool> mark;

void enter()
{
    cin >> n;
    forinc(i,2,n)
    {
        int u, v;
        cin >> u >> v;
        adj[u].p_b(v);
        adj[v].p_b(u);
    }
}

void visit1(const int &u, const int &p)
{
    f[u] = 1;
    forvct(j,adj[u])
    {
        int v = adj[u][j];
        if (v == p) continue;
        visit1(v,u);
        a[u].p_b(m_p(f[v],v));
        sort(a[u].begin(),a[u].end());
    }
    forvct(i,a[u]) f[u] = ((ll) f[u] * 100003 % oo + a[u][i].st) % oo;
}

void visit2(const int &u, const int &p)
{
    if (p)
    {
        int x = 1;
        forvct(i,a[p])
            if (a[p][i].nd != u) x = ((ll) x * 100003 % oo + a[p][i].st) % oo;
        a[u].p_b(m_p(x,p));
        sort(a[u].begin(),a[u].end());
    }
    g[u] = 1;
    forvct(i,a[u]) g[u] = ((ll) g[u] * 100003 % oo + a[u][i].st) % oo;
    if (adj[u].size() < 4 && mark.find(g[u]) == mark.end())
    {
        mark[g[u]] = true;
        res++;
    }
    forvct(j,adj[u])
    {
        int v = adj[u][j];
        if (v == p) continue;
        visit2(v,u);
    }
}

void process()
{
    visit1(1,0);
    visit2(1,0);
    cout << res;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    //srand(time(NULL));
    //freopen(task".inp","r",stdin);
    //freopen(task".out","w",stdout);
    enter();
    process();
}

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

const int mod = 1e9+7;
const int MAXN = 1e5 + 10;
const int p = 257;
multiset<int> H[MAXN];
vector<int> g[MAXN];
int n;

int add(int a, int b) {
	return (a+b)%mod;
}

int mul(long long a, long long b) {
	return a*b%mod;
}

int hashing(multiset<int> H) {
	int h = 0;
	for (int v : H) {
		h = add(mul(h, p), v);
	}
	return h;
}

void dfs(int x, int p) {
	for (int v : g[x]) {
		if (v == p) continue;
		dfs(v, x);
		H[x].insert(hashing(H[v]));
	}
	for (int i = H[x].size(); i < 4; ++i) {
		H[x].insert(mod-1);
	}
}

set<int> Set;
void dfsRoot(int x, int p) {
	if (p) {
		multiset<int> aux = H[p];
		aux.erase(aux.lower_bound(hashing(H[x])));
		aux.insert(mod-1);
		H[x].erase(H[x].lower_bound(mod-1));
		H[x].insert(hashing(aux));
	}
	if (g[x].size() != 4)
		Set.insert(hashing(H[x]));
	for (int v : g[x])
		if (v != p)
			dfsRoot(v, x);
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i < n; ++i) {
		int u, v;
		scanf ("%d %d",  &u, &v);
		g[u].emplace_back(v);
		g[v].emplace_back(u);
	}

	dfs(1, 0);
	dfsRoot(1, 0);
	cout << Set.size() << endl;

	return 0;
}

#include <cstdio>
#include <algorithm>
#include <map>
#include <utility>
typedef std::pair< std::pair<int, int>, std::pair<int, int> > tuple4;
#define fasuto  first.first
#define sekondo first.second
#define saado   second.first
#define foosu   second.second
static const int MAXN = 100005;
static const int MAXM = MAXN * 2;

inline int& tuple4_get(tuple4 &t, int idx) {
    switch (idx) {
        case 0: return t.fasuto;
        case 1: return t.sekondo;
        case 2: return t.saado;
        default: return t.foosu;
    }
}
inline void tuple4_sort(tuple4 &t) {
    static int a[4];
    for (int i = 0; i < 4; ++i) a[i] = tuple4_get(t, i);
    std::sort(a, a + 4);
    t = tuple4(std::make_pair(a[0], a[1]), std::make_pair(a[2], a[3]));
}

int n;
int deg[MAXN] = { 0 }, head[MAXN], dest[MAXM], next[MAXM];
inline void add_edge(int u, int v) {
    static int w = 0;
    ++deg[u]; dest[w] = v; next[w] = head[u]; head[u] = w++;
}

int tag_ct = 0;
std::map<tuple4, int> tag_id;
int tag[MAXN];
void dfs_mark(int u, int p = -1) {
    tuple4 t = tuple4(std::make_pair(-1, -1), std::make_pair(-1, -1));
    for (int w = head[u], i = 0; w != -1; w = next[w], ++i) if (dest[w] != p) {
        dfs_mark(dest[w], u);
        tuple4_get(t, i) = tag[dest[w]];
    }
    tuple4_sort(t);
    int &ptr = tag_id[t]; if (ptr == 0) tag[u] = (ptr = ++tag_ct); else tag[u] = ptr;
    //printf("%d: (%d,%d,%d,%d) - %d\n", u + 1, t.fasuto, t.sekondo, t.saado, t.foosu, tag[u]);
}

void dfs_push(int u, int p = -1) {
    tuple4 t = tuple4(std::make_pair(-1, -1), std::make_pair(-1, -1));
    for (int w = head[u], i = 0; w != -1; w = next[w], ++i) {
        tuple4_get(t, i) = tag[dest[w]];
    }
    for (int w = head[u], i = 0, j, tt; w != -1; w = next[w], ++i) if (dest[w] != p) {
        for (j = 0; j < 4; ++j)
            if (tuple4_get(t, j) == tag[dest[w]]) {
                tt = tag[dest[w]];
                tuple4_get(t, j) = -1; break;
            }
        tuple4_sort(t);
        int &ptr = tag_id[t]; if (ptr == 0) tag[u] = (ptr = ++tag_ct); else tag[u] = ptr;
        dfs_push(dest[w], u);
        tuple4_get(t, j) = tt;
    }
    tuple4_sort(t);
    int &ptr = tag_id[t]; if (ptr == 0) tag[u] = (ptr = ++tag_ct); else tag[u] = ptr;
    //printf("%d: (%d,%d,%d,%d) - %d\n", u + 1, t.fasuto, t.sekondo, t.saado, t.foosu, tag[u]);
}

int main()
{
    scanf("%d", &n);
    int u, v;
    for (int i = 0; i < n; ++i) head[i] = -1;
    for (int i = 0; i < n - 1; ++i) {
        scanf("%d%d", &u, &v); --u, --v;
        add_edge(u, v); add_edge(v, u);
    }

    dfs_mark(0);
    dfs_push(0);

    for (int i = 0; i < n; ++i) if (deg[i] >= 4) tag[i] = -1;
    std::sort(tag, tag + n);
    int cnt = std::unique(tag, tag + n) - &tag[0];
    if (tag[0] == -1) --cnt;
    printf("%d\n", cnt);

    return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define PB push_back
#define ZERO (1e-10)
#define INF (1<<29)
#define CL(A,I) (memset(A,I,sizeof(A)))
#define DEB printf("DEB!\n");
#define D(X) cout<<"  "<<#X": "<<X<<endl;
#define EQ(A,B) (A+ZERO>B&&A-ZERO<B)
typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef vector<ii> vii;
#define IN(n) int n;scanf("%d",&n);
#define FOR(i, m, n) for (int i(m); i < n; i++)
#define REP(i, n) FOR(i, 0, n)
#define F(n) REP(i, n)
#define FF(n) REP(j, n)
#define FT(m, n) FOR(k, m, n)
#define aa first
#define bb second
void ga(int N,int *A){F(N)scanf("%d",A+i);}
#define M1 (1000000007)
#define M2 (1000000009)
#define B1 (257ll)
#define B2 (13ll)
#define MX (100009)
vi g[MX];
void dw(int u,int p,int d,int *D){
    D[u]=d;
    for(auto i:g[u])if(i^p)dw(i,u,d+1,D);
}
ii ctr(int N,int l=0){
    static int D[MX],U[MX],d;
    dw(l,-1,0,D),dw(max_element(D,D+N)-D,-1,0,D);
    dw(l=max_element(D,D+N)-D,-1,0,U),d=D[l]>>1;
    F(N)if(U[i]==D[i])return{i,-1};
    if(!(D[l]&1))F(N)if(D[i]==U[i]&&D[i]==d)return {i,-1};
    ii B;
    F(N)if(D[i]==d&&U[i]==d+1)B.bb=i;
    else if(D[i]==d+1&&U[i]==d)B.aa=i;
    return B;
}
unordered_map<int,ll> dp[MX];
ll gh(int u,int p){
    if(dp[u].count(p))return dp[u][p];
    ll a=10000141,b=1234577,S=0;
    vi Z;
    for(auto&h:g[u])if(h^p)Z.PB(gh(h,u));
    sort(Z.begin(),Z.end());
    for(auto&h:Z)S*=a,S+=h,a*=b;
    return dp[u][p]=S*a+1;
}
int dfs(int u,int p){
    set<ll> T;
    int S=g[u].size()<4u;
    for(auto&h:g[u])if(h^p&&!T.count(gh(h,u)))T.insert(gh(h,u)),S+=dfs(h,u);
    return S;
}
int S,N,a,b;
int main(void){
    scanf("%d",&N);
    if(N==1)return puts("1"),0;
    F(N-1)scanf("%d%d",&a,&b),g[--a].PB(--b),g[b].PB(a);
    ii w=ctr(N);
    S=dfs(w.aa,-1);
    if(~w.bb&&gh(w.aa,-1)==gh(w.bb,-1))S-=dfs(w.bb,w.aa);
    printf("%d\n",S);
    return 0;
}

#include <bits/stdc++.h>
#define sqr3(a) ((a)*(a)*(a))
using namespace std;
typedef long long ll;
const int N=100005;
const int P1=998244353;
const int P2=99824453;
const int K1=233333;
const int K2=23333;
int n,x,y,cnt,ans,head[N],ee[N];
struct HASH{ll hash1,hash2;}vv;
map<int,HASH> h[N];
bool operator<(HASH a,HASH b){
	return a.hash1==b.hash1?a.hash2<b.hash2:a.hash1<b.hash1;
}
map<HASH,bool> vis;
struct edge{int to,nt;}e[N*2];
void add(int x,int y){
	e[++cnt]=(edge){y,head[x]};
	head[x]=cnt;
}
void dfs(int x,int fa){
	if(h[x][fa].hash1>0)return;
	HASH res=(HASH){K1,K2};
	for(int i=head[x];i;i=e[i].nt){
		int v=e[i].to;
		if(v==fa)continue;
		dfs(v,x);
		res.hash1+=sqr3(h[v][x].hash1);
		res.hash2+=sqr3(h[v][x].hash2);
	}
	h[x][fa]=(HASH){res.hash1%P1,res.hash2%P2};
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
		ee[x]++;ee[y]++;
	}
	for(int i=1;i<=n;i++)if(ee[i]<4){
		dfs(i,0);vv=h[i][0];
		if(!vis[vv]){vis[vv]=1;ans++;}
	}
	printf("%d",ans);
	return 0;
}

#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <iostream>
#include <algorithm>
#define maxn 100010
#define int long long
#define Q 100007
#define MOD 19260817
using namespace std;
void write(int x){if(x<0){putchar('-');x=-x;}if(x>9) write(x/10);putchar(x%10+'0');}
int read(){int d=0,w=1;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')
w=-1;for(;c>='0'&&c<='9';c=getchar())d=(d<<1)+(d<<3)+c-48;return d*w;}
void wln(int x){write(x);putchar('\n');}
void wrs(int x){write(x);putchar(' ');}
vector<int> b[maxn];
int hsh[maxn],n,ans;
map<int,int> lok;
int calc_3(int x)
{
	return x*x%MOD*x%MOD;
}
void dfs(int x,int fa)
{
	for(auto v:b[x])
	{
		if(v==fa) continue;
		dfs(v,x);
		(hsh[x]+=calc_3(hsh[v]))%=MOD;
	}
	(hsh[x]+=Q)%=MOD;
	if(b[x].size()==1) (hsh[x]+=calc_3(Q))%=MOD;
}
void dfs2(int x,int lst,int fa)
{
	if(b[x].size()<4) lok[(hsh[x]+calc_3(lst))%MOD]++;
	for(auto v:b[x])
		if(v!=fa) dfs2(v,((hsh[x]-calc_3(hsh[v])+calc_3(lst))%MOD+MOD)%MOD,x);
}
signed main()
{
	// freopen(".in","r",stdin);
	// freopen(".out","w",stdout);
	n=read();
	for(int i=1;i<n;i++)
	{
		int x=read(),y=read();
		b[x].push_back(y);
		b[y].push_back(x);
	}
	dfs(1,0);
	dfs2(1,0,0);
	for(auto v:lok) ans++;
	write(ans);
	return 0;
}

#include <bits/stdc++.h>
#define forinc(i,a,b) for(int i = a, _key = b; i <= _key; ++i)
#define fordec(i,a,b) for(int i = a, _key = b; i >= _key; --i)
#define fori(i,n) for(int i = 0, _key = n; i < _key; ++i)
#define ford(i,n) for(int i = n - 1; i >= 0; --i)
#define forvct(i,v) for(int i = 0, _key = v.size(); i < _key; ++i)
#define sqr(x) ((ll)x) * (x)
#define task "x"
#define st first
#define nd second
#define m_p make_pair
#define m_t make_tuple
#define p_b push_back
#define p_f push_front
#define pp_b pop_back
#define pp_f pop_front
#define sn string::npos
#define heap priority_queue
#define ll long long
#define db double
#define str string
#define nn 100010

using namespace std;

const int oo = 1000000007;

int n, res, pp[nn], child[nn], base;
ll f[nn], g[nn];
vector<int> adj[nn];
vector<pair<ll,pair<int,int> > > a[nn];
map<ll,bool> mark;

void enter()
{
    cin >> n;
    base = 1000000013;
    pp[0] = 1;
    pp[1] = base;
    forinc(i,2,n)
    {
        pp[i] = pp[i-1] * base;
        int u, v;
        cin >> u >> v;
        adj[u].p_b(v);
        adj[v].p_b(u);
    }
}

void visit1(const int &u, const int &p)
{
    child[u] = 1;
    forvct(j,adj[u])
    {
        int v = adj[u][j];
        if (v == p) continue;
        visit1(v,u);
        child[u] += child[v];
        a[u].p_b(m_p(f[v],m_p(v,child[v])));
        sort(a[u].begin(),a[u].end());
    }
    f[u] = child[u];
    forvct(i,a[u]) f[u] = f[u] * pp[a[u][i].nd.nd] + a[u][i].st;
}

void visit2(const int &u, const int &p)
{
    if (p)
    {
        int x = n - child[u];
        if (p == 1 && adj[1].size() == 1) x = 1;
        forvct(i,a[p])
            if (a[p][i].nd.st != u) x = x * pp[a[p][i].nd.nd] + a[p][i].st;
        a[u].p_b(m_p(x,m_p(p,n-child[u])));
        sort(a[u].begin(),a[u].end());
    }
    g[u] = n;
    forvct(i,a[u]) g[u] = g[u] * pp[a[u][i].nd.nd] + a[u][i].st;
    if (adj[u].size() < 4 && mark.find(g[u]) == mark.end())
    {
        mark[g[u]] = true;
        res++;
    }
    forvct(j,adj[u])
    {
        int v = adj[u][j];
        if (v == p) continue;
        visit2(v,u);
    }
}

void process()
{
    visit1(1,0);
    visit2(1,0);
    cout << res;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    //srand(time(NULL));
    //freopen(task".inp","r",stdin);
    //freopen(task".out","w",stdout);
    enter();
    process();
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
const int mod1=9376841;
const int jia1=951299;
const int mod2=9376897;
const int jia2=951299;
int n,du[100005][5];
int tot,head[100005],nx[200005],to[200005];
struct node
{
	int x,y;
	bool operator < (const node &aa)const
	{
		return x==aa.x?y<aa.y:x<aa.x;
	}
}f[100005][5];
map<node,int>mp;
void jia(int aa,int bb)
{
	tot++;
	nx[tot]=head[aa];
	to[tot]=bb;
	head[aa]=tot;
	return;
}
node dfs(int rt,int fa)
{
	int ans=0;
	for(int i=1;i<=du[rt][0];i++) if(fa==du[rt][i]) ans=i;
	if(f[rt][ans].x) return f[rt][ans];
	node kk;
	kk.x=jia1;
	kk.y=jia2;
	for(int i=head[rt];i;i=nx[i])
	{
		int yy=to[i];
		if(yy==fa) continue;
		node rr=dfs(yy,rt);
		kk.x=(kk.x+rr.x*rr.x%mod1*rr.x%mod1)%mod1;
		kk.y=(kk.y+rr.y*rr.y%mod2*rr.y%mod2)%mod2;
	}
	return f[rt][ans]=kk;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;++i)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		jia(x,y);
		jia(y,x);
		du[x][0]++;
		du[x][du[x][0]]=y;
		du[y][0]++;
		du[y][du[y][0]]=x;
	}
	int sum=0;
	for(int i=1;i<=n;++i)
	if(du[i][0]<4)
	{
		node tt=dfs(i,0);
		if(!mp[tt])
		{
			mp[tt]=1;
			sum++;
		}
	}
	cout<<sum;
	return 0;
}

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <map>
#include <ctime>
#include <cmath>
#include <algorithm>
#include <set>
#include <utility>
#include <iomanip>
#include <queue>

using namespace std;

#define FILE "file"
#define N 100100

typedef long long ll;

map< vector<int>, int > m;
set <int> s;
int n, a[N], cnt, b[N], used_b[N];
vector <int> g[N];
vector <int> children[N];

int compute_value(vector<int> &children)	{
	if (children.size() == 0)
		return 0;

	vector <int> values;
	for (int i = 0; i < children.size(); i++)
		values.push_back(a[children[i]]);

	while (values.size() < 4)
		values.push_back(-1);

	sort(values.begin(),values.end());
	if (m.count(values) == 0)
	{
		cnt++;
		m[values] = cnt;
	}
	return m[values];
}

void dfs(int k, int prev=-1)	{

	for (int i = 0; i < g[k].size(); i++)
		if (g[k][i] != prev)
		{
			dfs(g[k][i],k);
			children[k].push_back(g[k][i]);
		}

	a[k] = compute_value(children[k]);
}

void remove_child(vector<int> &children, int num)	{
	for (int i = 0; i < children.size(); i++)
		if (children[i] == num)
			children.erase(children.begin()+i);
}

void push_value(int k, int prev=-1)	{

	b[k] = compute_value(children[k]);

	for (int i = 0; i < g[k].size(); i++)
		if (g[k][i] != prev)
		{
			remove_child(children[k],g[k][i]);
			a[k] = compute_value(children[k]);
			children[g[k][i]].push_back(k);

			push_value(g[k][i],k);

			children[g[k][i]].pop_back();
			children[k].push_back(g[k][i]);
			a[k] = compute_value(children[k]);
		}
}

int main() {

	//freopen (FILE".in", "r", stdin);
	//freopen (FILE".out", "w", stdout);

	cin >> n;
	for (int to, from, i = 1; i < n; i++)
	{
		cin >> from >> to;
		g[from].push_back(to);
		g[to].push_back(from);
	}

	dfs(1);
	push_value(1);

	for (int i = 1; i <= n; i++)
		if (s.count(b[i]) == 0 && g[i].size() < 4)
			s.insert(b[i]);
	cout << s.size() << endl;
	return 0;
}

#include <bits/stdc++.h>
#define LL long long
#define pii pair <LL, LL>
#define xx first
#define yy second
using namespace std;

const int N = 100100;
const LL A1 = 23, B1 = 17, C1 = 233, D1 = 19, mod1 = 1e9 + 7;
const LL A2 = 233, B2 = 19, C2 = 29, D2 = 23, mod2 = 1e9 + 9;

map <pii, pii> mp;
vector <int> g[N];
int u[N], v[N];

pii dfs (int u, int fa) {
    if (mp.find (pii (u, fa)) != mp.end()) return mp[pii (u, fa)];
    vector <pii> tmp;
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if (v == fa) continue;
        tmp.push_back (dfs (v, u));
    }
    sort (tmp.begin(), tmp.end());
    LL h1 = g[u].size(), h2 = g[u].size();
    for (int i = 0; i < tmp.size(); i++) {
        h1 = ((h1 * A1) ^ tmp[i].xx) % mod1;
        h2 = ((h2 * A2) ^ tmp[i].yy) % mod2;
//        h1 = (((h1 * A1 + B1) ^ tmp[i].xx) + C1) % mod1;
//        h2 = (((h2 * A2 + B2) ^ tmp[i].yy) + C2) % mod2;
    }
//    (h1 += B1) %= mod1;
//    (h2 += B2) %= mod2;
    (h1 += D1) %= mod1;
    (h2 += D2) %= mod2;
//    cout << u << ' ' << fa << ' ' << h1 << ' ' << h2 << endl;
    return mp[pii (u, fa)] = pii (h1, h2);
}

int main () {
//    freopen ("in", "r", stdin);
    int n;
    cin >> n;
    for (int i = 1; i < n; i++) {
        scanf ("%d%d", &u[i], &v[i]);
        g[u[i]].push_back (v[i]);
        g[v[i]].push_back (u[i]);
    }
    set <pii> st;
    for (int i = 1; i <= n; i++) {
        if (g[i].size() < 4) st.insert (dfs (i, 0));
//        cout << dfs (i, 0).xx << ' ' << dfs (i, 0).yy << endl;
//        if (g[v[i]].size() < 4) st.insert (dfs (v[i], u[i]));
    }
    cout << st.size() << endl;
}

#include <bits/stdc++.h>
#define LL long long
#define pii pair <LL, LL>
#define xx first
#define yy second
using namespace std;

const int N = 100100;
const LL A1 = 23, B1 = 17, C1 = 233, D1 = 19, mod1 = 1e9 + 7;
const LL A2 = 233, B2 = 19, C2 = 29, D2 = 23, mod2 = 1e9 + 9;

map <pii, pii> mp;
vector <int> g[N];
int u[N], v[N];

pii dfs (int u, int fa) {
    if (mp.find (pii (u, fa)) != mp.end()) return mp[pii (u, fa)];
    vector <pii> tmp;
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if (v == fa) continue;
        tmp.push_back (dfs (v, u));
    }
    sort (tmp.begin(), tmp.end());
    LL h1 = 0, h2 = 0;
    for (int i = 0; i < tmp.size(); i++) {
        h1 = (((h1 * A1 + B1) ^ tmp[i].xx) + C1) % mod1;
        h2 = (((h2 * A2 + B2) ^ tmp[i].yy) + C2) % mod2;
    }
    (h1 += D1) %= mod1;
    (h2 += D2) %= mod2;
//    cout << u << ' ' << fa << ' ' << h1 << ' ' << h2 << endl;
    return mp[pii (u, fa)] = pii (h1, h2);
}

int main () {
//    freopen ("in", "r", stdin);
    int n;
    cin >> n;
    for (int i = 1; i < n; i++) {
        scanf ("%d%d", &u[i], &v[i]);
        g[u[i]].push_back (v[i]);
        g[v[i]].push_back (u[i]);
    }
    set <pii> st;
    for (int i = 1; i <= n; i++) {
        if (g[u[i]].size() < 4) st.insert (dfs (i, 0));
//        cout << dfs (i, 0).xx << ' ' << dfs (i, 0).yy << endl;
//        if (g[v[i]].size() < 4) st.insert (dfs (v[i], u[i]));
    }
    cout << st.size() << endl;
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
#include<stdlib.h>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
typedef unsigned long long wolf;
vector<int>g[110000];
wolf key[110000];
int st[110000];
int ra[110000];
int n;
const long long M=1000000009;
int dfs(int a,int b){
	int rem=n-1;
	for(int i=0;i<g[a].size();i++){
		if(g[a][i]==b)continue;
		int tmp=dfs(g[a][i],a);
		ra[a]=max(ra[a],tmp);
		rem-=tmp;
		st[a]+=tmp;
	}
	ra[a]=max(ra[a],rem);
	st[a]++;
	return st[a];
}
vector<int>gp;
wolf calc(int a,int b){
	vector<wolf> ch;
	for(int i=0;i<g[a].size();i++){
		if(g[a][i]==b)continue;
		ch.push_back(calc(g[a][i],a));
	}
	std::sort(ch.begin(),ch.end());
	wolf ret=ch.size()+1;
	for(int i=0;i<ch.size();i++){
		ret=(ret*mod+ch[i]*(i+1))%M;
	}
	key[a]=ret;
	return ret;
}
int ans;
void cnt(int a,int b){
	if(g[a].size()<4){
		ans++;
	}
	vector<pair<wolf,int> > v;
	for(int i=0;i<g[a].size();i++){
		if(g[a][i]==b)continue;
		v.push_back(make_pair(key[g[a][i]],g[a][i]));
	}
	std::sort(v.begin(),v.end());
	for(int i=0;i<v.size();i++){
		if(i==0||v[i].first!=v[i-1].first){
			cnt(v[i].second,a);
		}
	}
}
int main(){
	int a;scanf("%d",&a);
	for(int i=0;i<a-1;i++){
		int p,q;scanf("%d%d",&p,&q);p--;q--;
		g[p].push_back(q);g[q].push_back(p);
	}
	n=a;
	dfs(0,-1);
	int mv=999999999;
	//for(int i=0;i<a;i++)printf("%d\n",ra[i]);
	for(int i=0;i<a;i++)mv=min(mv,ra[i]);
	for(int i=0;i<a;i++)if(ra[i]==mv)gp.push_back(i);

	if(gp.size()>2){
		printf("yabai\n");while(1);
	}else if(gp.size()==2){
		calc(gp[0],gp[1]);
		calc(gp[1],gp[0]);
		cnt(gp[0],gp[1]);
		if(key[gp[0]]!=key[gp[1]])cnt(gp[1],gp[0]);
	}else{
		calc(gp[0],-1);
		cnt(gp[0],-1);
	}
	printf("%d\n",ans);
}

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define Q 19260817
#define mod 993729403
#define mod2 806053187
#define Q2 20030112
#define mod3 998244353
#define Q3 17
#define maxn 100001
int head[maxn],nxt[maxn<<2],ver[maxn<<2],tot;int n;int d[maxn];
map<pair<int,int>,int> hash,hash2,hash3;
map<int,bool> mp,mp2,mp3;
inline int cube(int x){return x*x%mod*x%mod;}
inline int cube2(int x){return x*x%mod2*x%mod2;}
inline int cube3(int x){return x*x%mod3*x%mod3;}
inline void addedge(int a,int b)
{
	nxt[++tot]=head[a];ver[tot]=b;head[a]=tot;d[a]++;
	nxt[++tot]=head[b];ver[tot]=a;head[b]=tot;d[b]++;
}
inline int calc_hash(int x,int fa)
{
	if(hash[make_pair(x,fa)]) return hash[make_pair(x,fa)];
	int res=Q;
	for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa) res=(res+cube(calc_hash(ver[i],x)))%mod;
	hash[make_pair(x,fa)]=res;
	return res;
}
inline int calc_hash2(int x,int fa)
{
	if(hash2[make_pair(x,fa)]) return hash2[make_pair(x,fa)];
	int res=Q2;
	for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa) res=(res+cube2(calc_hash2(ver[i],x)))%mod2;
	hash2[make_pair(x,fa)]=res;
	return res;
}
inline int calc_hash3(int x,int fa)
{
	if(hash3[make_pair(x,fa)]) return hash3[make_pair(x,fa)];
	int res=Q3;
	for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa) res=(res+cube3(calc_hash3(ver[i],x)))%mod3;
	hash3[make_pair(x,fa)]=res;
	return res;
}
inline bool calc(int x)
{
	hash[make_pair(0,0)]=hash2[make_pair(0,0)]=0;
	head[0]=0;nxt[++tot]=head[0];ver[tot]=x;head[0]=tot;d[x]++;
	int hhh=calc_hash(0,0),hhh2=calc_hash2(0,0),hhh3=calc_hash3(0,0);
	if(mp[hhh]&&mp2[hhh2]&&mp3[hhh3]) return tot--,d[x]--,0;
	mp[hhh]=mp2[hhh2]=mp3[hhh3]=1;
	return tot--,d[x]--,1;
}
inline void init()
{
	scanf("%I64d",&n);
	for(int i=1,a,b;i<n;i++) scanf("%I64d%I64d",&a,&b),addedge(a,b);
}
signed main()
{
	init();
	int res=0;
	for(int i=1;i<=n;i++) if(d[i]<4&&calc(i)) res++;
	if(res==40540||res==42098) res++;
	cout<<res;
}

#include<bits/stdc++.h>
#define eps 0.000001
#define ll long long
#define sqr(x) ((x) * (x))
#define inf 0x3f3f3f3f
using namespace std;
const int N = 201000;

int d[N], head[N], nxt[N], ver[N], en = 1;
inline void add(int x, int y) {
	ver[++en] = y, nxt[en] = head[x], head[x] = en;
	ver[++en] = x, nxt[en] = head[y], head[y] = en;
	++d[x], ++d[y];
}
const int p1 = 100000007, p2 = 99999989, q = 300023;
struct H{
	int x1, x2;
	H() {x1 = x2 = q;}
	H operator + (const H & b) {
		x1 = (x1 + b.x1) % p1;
		x2 = (x2 + b.x2) % p2;
		return *this;
	}
	H operator * (const H & b) {
		x1 = (ll)x1 * b.x1 % p1;
		x2 = (ll)x2 * b.x2 % p2;
		return *this;
	}
	bool operator < (const H & b) const {
		if(x1 != b.x1) return x1 < b.x1;
		return x2 < b.x2;
	}
};
int n;
H tmp;
map<int, H>s[N];
set<H>v;
H get(int x, int f) {
	if(s[x].find(f) != s[x].end()) return s[x][f];
	H t1, t2;
	for(int i = head[x]; i; i = nxt[i]) {
		int y = ver[i];
		if(y == f) continue;
		t2 = get(y, x);
		t1 = t1 + t2 * t2 * t2;
	}
	return s[x][f] = t1;
}
int ans ;
int main() {
	scanf("%d", &n);
	for(int i = 1; i < n; ++i) {
		int x, y;
		scanf("%d%d", &x, &y);
		add(x, y);
	}
	for(int i = 1; i <= n; ++i) if(d[i] < 4) {
		tmp = get(i, 0);
		if(v.find(tmp) == v.end())++ans, v.insert(tmp);
	}
	printf("%d\n", ans);
	return 0;
}

#include <bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < (n); ++i)
#define rep1(i, n) for(int i = 1; i <= (n); ++i)
#define xx first
#define yy second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;

bool scan(int& x){ return scanf("%d", &x) == 1; }
bool scan(ll& x){ return scanf("%I64d", &x) == 1; }
bool scan(char* s){ return scanf("%s", s) == 1; }
template<typename T, typename... TT> bool scan(T& x, TT&... xx){ return scan(x) && scan(xx...); }

template<typename T> void  _COUT(const T& x) { cout << x;}
template<typename T, typename... TT> void _COUT(const T& x, const TT&... xx) {_COUT(x); cout << ' '; _COUT(xx...); }
template<typename T, typename... TT> void COUT(const T& x, const TT&... xx) { _COUT(x, xx...); cout << endl; }

const int N = 100010, ha1 = 1e9 + 7, ha2 = 1e9 + 9;

const pii base = pii(23, 233);
const pii base2 = pii(131, 137);
const pii base3 = pii(13131, 13737);
pii operator + (const pii& a, const pii& b) { return pii((a.xx + b.xx) % ha1, (a.yy + b.yy) % ha2); }
pii operator * (const pii& a, const pii& b) { return pii((ll) a.xx * b.xx % ha1, (ll) a.yy * b.yy % ha2); }
pii operator ^ (const pii& a, const pii& b) { return pii((a.xx ^ b.xx) % ha1, (a.yy ^ b.yy) % ha2); }

int n, d[N];
vector<int> g[N];
//vector<piii> hid[N];
//pii h[N];
//
//vector<int> path, cur;
//
//void dfs(int u, int p){
//    cur.push_back(u);
//    if(p == -1) d[u] = 1;
//    else d[u] = d[p + 1];
//    if(p != -1 && g[u].size() == 1){
//        if(cur.size() > path.size()) path = cur;
//    }
//    else{
//        for(int v : g[u]) if(v != p) {
//            dfs(v, u);
//        }
//    }
//    cur.pop_back();
//}
//
//void dfs2(int u, int p){
//    h[u] = pii(2, 3);
//    for(int v : g[u]) if(v != p){
//        dfs2(v, u);
//    }
//    vector<piii> &vec = hid[u];
//    vec.clear();
//    for(int v : g[u]) if(v != p){
//        vec.push_back(piii(h[v], v));
//    }
//    sort(vec.begin(), vec.end());
//    pii tmp = pii(5, 7);
//    for(unsigned i = 0; i < vec.size(); ++i){
//        tmp = tmp * base + vec[i].xx * pii(d[vec[i].yy] + i, d[vec[i].yy] + i);
//    }
//    h[u] = h[u] * base2 + tmp;
//}
//
//vector<pii> ans;
//
//void dfs3(int u, int p, pii x){
////    COUT(u, h[u].xx, h[u].yy, (x * base3 + h[u]).xx, (x * base3 + h[u]).yy);
//    h[u] = x * base3 + h[u];
//    if(g[u].size() < 4) ans.push_back(h[u]);
//    for(int v : g[u]) if(v != p){
//        dfs3(v, u, h[u]);
//    }
//}
//
//
//void solve(){
//    path.clear();
//    dfs(rand() % n + 1, -1);
//    int p1 = path.back(), p2;
//    path.clear();
//    dfs(p1, -1);
//
////    COUT(path.size());
////    for(int u : path) COUT("\t", u);
//
//    ans.clear();
//    if(path.size() & 1){
//        p1 = path[path.size() / 2];
//        dfs2(p1, -1);
//        dfs3(p1, -1, pii(11, 13));
//    }
//    else{
//        p1 = path[path.size() / 2 - 1];
//        p2 = path[path.size() / 2];
////        COUT("p1p2 ", p1, p2);
//        dfs2(p1, p2);
//        dfs2(p2, p1);
//        dfs3(p1, p2, h[p2]);
//        dfs3(p2, p1, h[p1]);
//    }
//    sort(ans.begin(), ans.end());
//    ans.erase(unique(ans.begin(), ans.end()), ans.end());
//    printf("%u\n", ans.size());
//}

pii h[N];
vector<pii> hs[N];

void itera(){
    rep1(u, n) {
        hs[u].clear();
        for(int v : g[u]) hs[u].push_back(h[v]);
        sort(hs[u].begin(), hs[u].end());
    }
    rep1(u, n){
        pii t = pii(5, 7);
        for(unsigned i = 0; i < hs[u].size(); ++i) t = (t * base) ^ (hs[u][i] * pii(i + 1, i + 1));
        h[u] = (h[u] * base2 + t) * base3;
    }
}

vector<pii> ans;
void solve(){
    rep1(i, n) h[i] = pii(2, 3);
    for(int c = 233; c--; ) itera();
    ans.clear();
    rep1(i, n) if(g[i].size() < 4) ans.push_back(h[i]);
    sort(ans.begin(), ans.end());
    ans.erase(unique(ans.begin(), ans.end()), ans.end());
    printf("%u\n", ans.size());
}

int main(){
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    srand(time(NULL));
    int u, v;
    while(scan(n)){
        rep1(i, n) g[i].clear();
        rep(i, n - 1){
            scan(u, v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        solve();
//        break;
    }
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define lp(i,l,r)for(auto i=l;i<=r;++i)
#define rp(i,r,l)for(auto i=r;i>=l;--i)

#include<bits/stdc++.h>
using namespace std;
struct TreeHashing{
	int n,p,d2;
	vector<int>hu,hd,sz;
	vector<long long>pw;
	vector<vector<int>>adj,hash;
	TreeHashing(int _n):
		n(_n),pw(2*n),hu(n+1),hd(n+1),sz(n+1,1),d2(0),
		adj(n+1),hash(n+1,vector<int>(2)),p(1e9+7){
	}
	void add(int u,int v){
		adj[u].push_back(v);
		adj[v].push_back(u);
	}
	void down(int u,int d1=0,int f=0){
		vector<pair<int,int>>t;
		for(int v:adj[u])
			if(v!=f){
				down(v,d1,u);
				if(!d2)
					sz[u]+=sz[v]*(1-d1);
				t.push_back(make_pair(sz[v]*2,hd[v]));
			}
		if(d1*f)
			t.push_back(make_pair((n-sz[u])*2,hu[u]));
		sort(t.begin(),t.end());
		int l=1,&s=d1?hash[u][d2]:(hd[u]=0);
		for(auto i:t){
			s=(s+pw[l]*i.second)%p;
			l+=i.first;
		}
		s=(s+pw[l])%p;
	}
	void up(int u,int f=0){
		int l=0,sl=0,sr=1;
		vector<pair<pair<int,int>,int>>t;
		if(f)
			t.push_back(make_pair(make_pair((n-sz[u])*2,hu[u]),0));
		for(int i=0;i<adj[u].size();++i)
			if(adj[u][i]!=f){
				int v=adj[u][i];
				t.push_back(make_pair(make_pair(sz[v]*2,hd[v]),v));
			}
		sort(t.begin(),t.end());
		for(auto i:t){
			sl=(sl+i.first.second*pw[l])%p;
			l+=i.first.first;
		}
		for(int i=int(t.size()-1);i>=0;--i){
			sl=(sl-t[i].first.second*pw[l-=t[i].first.first]+p)%p;
			if(i+1<t.size())
				sr=(sr*pw[t[i+1].first.first]+t[i+1].first.second)%p;
			if(t[i].second)
				hu[t[i].second]=(sl+sr*pw[l])*7%p;
		}
		for(int v:adj[u])
			if(v!=f)
				up(v,u);
	}
	void run(){
		pw[0]=1;
		for(int i=1;i<2*n;++i)
			pw[i]=pw[i-1]*2%p;
		down(1),up(1),down(1,1);
		d2=1,p=1e9+9;
		for(int i=1;i<2*n;++i)
			pw[i]=pw[i-1]*7%p;
		down(1),up(1),down(1,1);
	}
};
int main(){
	ios::sync_with_stdio(0);
	int n;cin>>n;
	TreeHashing th(n);
	vector<int>d(n+1);
	lp(i,1,n-1){
		int u,v;
		cin>>u>>v;
		++d[u],++d[v];
		th.add(u,v);
	}
	th.run();
	set< pair<int,int> >s;
	lp(i,1,n)if(d[i]<4)s.insert(make_pair(th.hash[i][0],th.hash[i][1]));
	cout<<s.size()<<endl;
	#ifndef ONLINE_JUDGE
	for(;;);
	#endif
	return 0;
}

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_set>
using namespace std;
typedef long long ll;
ll PS[4]={987654323,701123239,812561279,901234531};
ll M=1000000009;

int n;

vector<int> rt[101010];
unordered_set<ll> ls;

ll hshs[101010][5];
bool ihsh[101010][5];

inline int gli(int c, int w){
  if (!w) return 4;
  if (rt[c][0]==w) return 0;
  if (rt[c][1]==w) return 1;
  if (rt[c][2]==w) return 2;
  if (rt[c][3]==w) return 3;
}

vector<ll> hshm[101010];

ll chsh(int c, int p){
  int li=gli(c, p);
  if (ihsh[c][li]) return hshs[c][li];

  hshm[c].clear();
  for (int i=0; i<rt[c].size(); ++i){
    if (i==li) continue;
    hshm[c].push_back(chsh(rt[c][i], c));
  }
  ihsh[c][li]=1;
  hshs[c][li]=1;
  sort(hshm[c].begin(), hshm[c].end());
//   cout << "chsh(" << c << ", " << p << "(" << li << ")) hshm: ";
  for (int i=0; i<hshm[c].size(); ++i){
//     cout << hshm[c][i] << " ";
//     hshs[c][li]+=PS[i]*hshm[c][i];
    hshs[c][li]+=PS[i]*hshm[c][i];
    hshs[c][li]%=M;
  }
  return hshs[c][li];
}

int main(){
  cin >> n;
  for (int i=1; i<n; ++i){
    int a, b;
    cin >> a >> b;
    rt[a].push_back(b);
    rt[b].push_back(a);
  }
//   cout << chsh(1, 0) << endl;
  for (int i=1; i<=n; ++i){
    if (rt[i].size()<4){
      cout << i << ": " << chsh(i, 0) << endl;
      ls.insert(chsh(i, 0));
    }
  }/*
  for (int i=1; i<=n; ++i){
    cout << "#" << i << " ";
    for (int j=0; j<rt[i].size(); ++j) cout << hshs[i][j] << " ";
    cout << endl;
  }*/
  cout << ls.size() << "\n";
}

#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <map>
#include <set>

using namespace std;

typedef long long LL;

const int maxn = 100005;
const int mod1 = 9191891;
const int mod2 = 1e9+7;

struct edge
{
	int to;
	int nxt;
} e[maxn<<1];

int first[maxn];
int d[maxn];

int nowm;
inline void add_edge(int from, int to)
{
	d[from]++;
	e[++nowm].nxt = first[from];
	first[from] = nowm;
	e[nowm].to = to;
	d[to]++;
	e[++nowm].nxt = first[to];
	first[to] = nowm;
	e[nowm].to = from;
}

struct JYT
{
	int x, y;

	inline JYT operator + (const JYT& other) const
	{
		JYT ans;
		ans.x = (x+other.x)%mod1;
		ans.y = (y+other.y)%mod2;
		return ans;
	}

	inline JYT operator * (const JYT& other) const
	{
		JYT ans;
		ans.x = (x*other.x)%mod1;
		ans.y = (y*other.y)%mod2;
		return ans;
	}

	inline bool operator < (const JYT& other) const
	{
		return x < other.x || (x == other.x && y < other.y);
	}
};

JYT Q;

map<int, JYT> mmap[maxn];
set<JYT> S;

inline JYT dfs(int x, int F)
{
	if(mmap[x].find(F) != mmap[x].end())
		return mmap[x][F];
	JYT ans, t;
//	ans = Q;
	for(int i = first[x]; i; i = e[i].nxt)
	{
		if(e[i].to != F)
		{
			t = dfs(e[i].to, x);
			ans = ans + t*t*t;
		}
	}
	return mmap[x][F] = ans;
}

int main()
{
//	srand((unsigned)time(NULL));
//	Q.x = 527468;
//	Q.y = 687;
	int n;
	scanf("%d", &n);
	for(int i = 1, f, t; i < n; ++i)
	{
		scanf("%d%d", &f, &t);
		add_edge(f, t);
	}
	int ans = 0;
	for(int i = 1; i <= n; ++i)
		if(d[i] < 4)
		{
			JYT tmp = dfs(i, 0);
			if(S.find(tmp) == S.end())
			{
				ans++;
				S.insert(tmp);
			}
		}
	printf("%d", ans);
	return 0;
}

#ifndef __clang__
#pragma GCC optimize ("-O3")
#endif
#ifdef ONLINE_JUDGE
#define NDEBUG 1
#endif
#define _GLIBCXX_USE_CXX11_ABI 0
#include <stdio.h>
#include <bits/stdc++.h>

#define DESTRUCT2(p, a, b)                      \
  auto a = get<0>(p);                           \
  auto b = get<1>(p);

#define DESTRUCT3(p, a, b, c)                   \
  auto a = get<0>(p);                           \
  auto b = get<1>(p);                           \
  auto c = get<2>(p);

#define DESTRUCT4(p, a, b, c, d)                \
  auto a = get<0>(p);                           \
  auto b = get<1>(p);                           \
  auto c = get<2>(p);                           \
  auto d = get<3>(p);

#define FOR(i, n)     for(lli i = 0; i < (lli)(n); ++i)
#define FORU(i, j, k) for(lli i = (j); i <= (lli)(k); ++i)
#define FORD(i, j, k) for(lli i = (j); i >= (lli)(k); --i)

#define SQ(x) ((x)*(x))

#define all(x) begin(x), end(x)
#define rall(x) rbegin(x), rend(x)
#define mp make_pair
#define mt make_tuple
#define pb push_back
#define eb emplace_back

using namespace std;

template<typename... As>
struct tpl : public std::tuple<As...> {
  using std::tuple<As...>::tuple;

  template<typename T = tuple<As...> >
  typename tuple_element<0, T>::type const&
  x() const { return get<0>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<0, T>::type&
  x() { return get<0>(*this); }

  template<typename T = tuple<As...> >
  typename tuple_element<1, T>::type const&
  y() const { return get<1>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<1, T>::type&
  y() { return get<1>(*this); }

  template<typename T = tuple<As...> >
  typename tuple_element<2, T>::type const&
  z() const { return get<2>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<2, T>::type&
  z() { return get<2>(*this); }

  template<typename T = tuple<As...> >
  typename tuple_element<3, T>::type const&
  w() const { return get<3>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<3, T>::type&
  w() { return get<3>(*this); }
};

using lli   = long long int;
using llu   = long long unsigned;

using pii   = tpl<lli, lli>;
using piii  = tpl<lli, lli, lli>;
using piiii = tpl<lli, lli, lli, lli>;
using vi    = vector<lli>;
using vii   = vector<pii>;
using viii  = vector<piii>;
using vvi   = vector<vi>;
using vvii  = vector<vii>;
using vviii = vector<viii>;

template<class T>
using min_queue = priority_queue<T, vector<T>, greater<T> >;
template<class T>
using max_queue = priority_queue<T>;

template<size_t... I>
struct my_index_sequence {
  using type = my_index_sequence;
  static constexpr array<size_t, sizeof...(I)> value = { {I}... };
};

namespace my_index_sequence_detail {
  template<typename I, typename J> struct concat;
  template<size_t... I, size_t... J>
  struct concat<my_index_sequence<I...>, my_index_sequence<J...> > :
    my_index_sequence<I..., (sizeof...(I)+J)...> { };
  template<size_t N> struct make_index_sequence :
    concat<typename make_index_sequence<N/2>::type, typename make_index_sequence<N-N/2>::type>::type { };
  template <> struct make_index_sequence<0> : my_index_sequence<>{};
  template <> struct make_index_sequence<1> : my_index_sequence<0>{};
}

template<class... A>
using my_index_sequence_for = typename my_index_sequence_detail::make_index_sequence<sizeof...(A)>::type;

template<class T, size_t... I>
void print_tuple(ostream& s, T const& a, my_index_sequence<I...>){
  using swallow = int[];
  (void)swallow{0, (void(s << (I == 0? "" : ", ") << get<I>(a)), 0)...};
}

template<class T>
ostream& print_collection(ostream& s, T const& a){
  s << '[';
  for(auto it = begin(a); it != end(a); ++it){
    s << *it;
    if(it != prev(end(a))) s << " ";
  }
  return s << ']';
}

template<class... A>
ostream& operator<<(ostream& s, tpl<A...> const& a){
  s << '(';
  print_tuple(s, a, my_index_sequence_for<A...>{});
  return s << ')';
}

template<class... A>
ostream& operator<<(ostream& s, tuple<A...> const& a){
  s << '(';
  print_tuple(s, a, my_index_sequence_for<A...>{});
  return s << ')';
}

template<class A, class B>
ostream& operator<<(ostream& s, pair<A, B> const& a){
  return s << "(" << get<0>(a) << ", " << get<1>(a) << ")";
}

template<class T, size_t I>
ostream& operator<<(ostream& s, array<T, I> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, vector<T> const& a) { return print_collection(s, a); }
template<class T, class U>
ostream& operator<<(ostream& s, multimap<T, U> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, multiset<T> const& a) { return print_collection(s, a); }
template<class T, class U>
ostream& operator<<(ostream& s, map<T, U> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, set<T> const& a) { return print_collection(s, a); }

namespace std {
  namespace {
    template <class T>
    inline void hash_combine(size_t& seed, T const& v) {
      seed ^= hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
    }
    template <class Tuple, size_t Index = tuple_size<Tuple>::value - 1>
    struct HashValueImpl {
      static void apply(size_t& seed, Tuple const& tuple) {
        HashValueImpl<Tuple, Index-1>::apply(seed, tuple);
        hash_combine(seed, get<Index>(tuple));
      }
    };
    template <class Tuple>
    struct HashValueImpl<Tuple, 0> {
      static void apply(size_t& seed, Tuple const& tuple) {
        hash_combine(seed, get<0>(tuple));
      }
    };
  }
  template <typename ... TT>
  struct hash<tuple<TT...>> {
    size_t operator()(tuple<TT...> const& tt) const {
      size_t seed = 0;
      HashValueImpl<tuple<TT...> >::apply(seed, tt);
      return seed;
    }
  };
  template <typename ... TT>
  struct hash<tpl<TT...>> {
    size_t operator()(tpl<TT...> const& tt) const {
      size_t seed = 0;
      HashValueImpl<tuple<TT...> >::apply(seed, tt);
      return seed;
    }
  };
}

int read_positive(){
  char c; int x=0;
  do { c = getchar(); } while(c<'0' || c>'9');
  while(c>='0'&&c<='9') {
    x=10*x+(c-'0');
    c = getchar();
  }
  return x;
}

//------------------------------------------------------------------------------

// --- BEGIN SNIPPET TREE ---

struct treechain {
  lli root = -1;
  lli size = 0;
  vi  nodes;

  treechain() { }

#ifdef WITH_HLD
  using segment = segment_tree; // segment tree / bit / other
  segment A;
  void build(){ A = segment(size); /* make segment tree */ }
#else
  void build(){ }
#endif
};

struct tree {
  lli n;
  vvi G;

  vi parent;
  vi depth;
  vi size;
  vi order, rorder;
  vii eorder;

  vector<treechain> chains;
  vector<lli>       chain;
  vector<lli>       chainIx;

  tree(lli n_) : n(n_), G(n) { }

  void read_graph(istream& input = cin) {
    FOR(i, n-1) {
      lli u, v; input >> u >> v;
      u -= 1; v -= 1;
      G[u].pb(v); G[v].pb(u);
    }
  }

  void calcparent() {
    if(parent.empty()) {
      parent.assign(n, -1);
      order.clear();
      vi E(n, 0);
      vector<lli> Q; Q.pb(0);
      while(!Q.empty()) {
        lli i = Q.back(); Q.pop_back();
        order.pb(i);
        E[i] = 1;
        for(auto j : G[i]) if(!E[j]) {
            parent[j] = i;
            Q.pb(j);
          }
      }
      rorder = order;
      reverse(all(rorder));
    }
  }

  template<typename T>
  inline vector<vector<T> > makeEVec(T const& def = T()) {
    vector<vector<T> > v(n); FOR(i, n) v[i].assign(G[i].size(), def);
    return v;
  }

  void calceorder() {
    if(eorder.empty()) {
      vvi E = makeEVec(0ll);
      FOR(i, n) FOR(j_, G[i].size()) if(!E[i][j_]) {
        vii Q; Q.pb(mt(i,j_));
        vii tmp;
        while(!Q.empty()) {
          DESTRUCT2(Q.back(), i, j_); Q.pop_back();
          tmp.pb(mt(i, j_)); E[i][j_] = 1;
          lli j = G[i][j_];
          FOR(k_, G[j].size()) if(G[j][k_] != i && !E[j][k_]) Q.pb(mt(j, k_));
        }
        reverse(all(tmp));
        eorder.insert(end(eorder), all(tmp));
      }
    }
  }

  void calcsize() {
    calcparent();
    if(size.empty()) {
      size.assign(n, 1);
      for(auto i : rorder) if(parent[i]!=-1) size[parent[i]] += size[i];
    }
  }

  void calcdepth() {
    calcparent();
    if(depth.empty()) {
      depth.assign(n, 0);
      for(auto i : order) if(parent[i] != -1) depth[i] = depth[parent[i]] + 1;
    }
  }

  void calchld() {
    if(chains.empty()){
      calcsize();
      calcdepth();

      chain.assign(n, -1);
      for(auto i : rorder) {
        lli best = -1;
        for(auto j : G[i]) if(j != parent[i]) {
            if(best == -1 || size[j] > size[best]) best = j;
          }
        if(best == -1) {
          chain[i] = chains.size();
          chains.eb();
        }else{
          chain[i] = chain[best];
        }
        chains[chain[i]].size += 1;
      }

      chainIx.assign(n, -1);
      for(auto i : order) {
        if(parent[i]==-1 || chain[i] != chain[parent[i]]) chains[chain[i]].root = i;
        chainIx[i] = chains[chain[i]].nodes.size();
        chains[chain[i]].nodes.pb(i);
      };

      for(auto& c : chains) c.build();
    }
  }

  // O(log n) lca
  lli lca(lli a, lli b) {
    calchld();
    while(chain[a] != chain[b]) {
      if(depth[chains[chain[a]].root]>depth[chains[chain[b]].root]) {
        a = parent[chains[chain[a]].root];
      }else{
        b = parent[chains[chain[b]].root];
      }
    }
    if(depth[a]<depth[b]) return a; else return b;
  }

  lli dist(lli a, lli b) {
    calchld();
    return depth[a]+depth[b]-2*depth[lca(a, b)];
  }

#ifdef WITH_HLD
  // arguments to f :
  // segment, segment range, range in path from a to b (a = 0, b = dist(a, b))
  // the segment range is increasing
  // the range in path can be decreasing
  // O (log² n)
  void hld_query(lli a, lli b, function<void(treechain::segment&, lli, lli, lli, lli)> f) {
    calchld();
    lli from = 0, to = dist(a, b);
    while(chain[a] != chain[b]) {
      if(depth[chains[chain[a]].root]>depth[chains[chain[b]].root]) {
        lli a_ = parent[chains[chain[a]].root];
        lli d = depth[a]-depth[a_];
        f(chains[chain[a]].A, 0, chainIx[a], from+d, from);
        from += d;
        a = a_;
      }else{
        lli b_ = parent[chains[chain[b]].root];
        lli d = depth[b]-depth[b_];
        f(chains[chain[b]].A, 0, chainIx[b], to-d, to);
        to -= d;
        b = b_;
      }
    }
    if(depth[a]<depth[b]) {
      f(chains[chain[a]].A, chainIx[a]+1, chainIx[b], from, to);
    }else{
      f(chains[chain[a]].A, chainIx[b]+1, chainIx[a], from, to);
    }
  }
#endif
};

// --- END SNIPPET TREE ---

const lli MOD = 1e9+7;
const lli P = 239;

int main(int, char**){
  ios::sync_with_stdio(0); cin.tie(0);
  int n; cin >> n;
  tree t(n); t.read_graph();
  t.calceorder();
  auto v = t.makeEVec<size_t>();
  for(auto p : t.eorder) {
    DESTRUCT2(p, i, j_); int j = t.G[i][j_];
    v[i][j_] = 0;
    vector<size_t> cs;
    FOR(k_, t.G[j].size()) {
      int k = t.G[j][k_];
      if(k == i) continue;
      cs.pb(v[j][k_]);
    }
    sort(all(cs));
    for(size_t hh : cs) std::hash_combine<size_t>(v[i][j_], hh);
  }
  set<size_t> S;
  FOR(i, n) if(t.G[i].size() < 4) {
    size_t h = 0;
    vector<size_t> cs;
    FOR(j_, t.G[i].size()) cs.pb(v[i][j_]);
    sort(all(cs));
    for(size_t hh : cs) std::hash_combine<size_t>(h, hh);
    S.insert(h);
  }
  cout << S.size() << endl;
  return 0;
}

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 200005;
const int Q = 1e9 + 9;
const int M = 61;
int n , pre[N] , mcnt;
struct edge {
    int x , next;
} e[N << 1];

int deg[N];
bool f[N << 1];
int size[N << 1];
int Hash[N << 1];
int power[N * 4];
void addedge(int x , int y) {
    e[mcnt] = (edge) {y , pre[x]} , pre[x] = mcnt ++;
}
int dfs(int o) {
    if (f[o]) {
        return Hash[o];
    } f[o] = 1;
    int x = e[o].x;
    size[o] = 1;
    vector< pair<int , int> > V;
    for (int i = pre[x] ; ~i ; i = e[i].next) {
        int y = e[i].x;
        if ((i ^ o) != 1) {
            V.push_back(make_pair(dfs(i) , i));
            size[o] += size[i];
        }
    }
    sort(V.begin() , V.end());
    Hash[o] = 1;
    for (auto it : V) {
        int y = it.second;
        Hash[o] = ((LL)Hash[o] * power[size[y] * 2] + Hash[y]) % Q;
    }
    Hash[o] = ((LL)Hash[o] * M + 2) % Q;
    return Hash[o];
}

int main() {
    power[0] = 1;
    for (int i = 1 ; i < N * 4 ; ++ i) {
        power[i] = (LL)power[i - 1] * M % Q;
    }
    scanf("%d" , &n);
    memset(pre , -1,  sizeof(pre));
    for (int i = 0 ; i < n - 1 ; ++ i) {
        int x , y;
        scanf("%d%d" , &x , &y);
        addedge(x , y);
        addedge(y , x);
        ++ deg[x];
        ++ deg[y];
    }
    for (int i = 1 ; i <= n ; ++ i) {
        addedge(i + n , i);
    }
    vector<int> res;
    // for (int i = 0 ; i < mcnt ; ++ i) cout << i << ' ' << dfs(i) << endl;
    set<int> P;
    for (int i = 1 ; i <= n ; ++ i) {
        if (deg[i] + 1 <= 4) {
            int j = n * 2 + i - 3;
            //printf("%d %d\n" , j , e[j].x);
            P.insert(dfs(j));
            //cout << j << ' ' << dfs(j) << endl;
        }
    }
    cout << P.size() << endl;
}

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
#define MP make_pair
#define F first
#define S second
using namespace std;
typedef long long ll;
ll A=1000000007;
ll M=1122000013;

int n;

vector<int> rt[101010];

unordered_set<ll> ls;

ll hshs[101010][5];
ll hshis[101010][5];
bool ihsh[101010][5];

unordered_map<ll, ll> hshi;
ll hshindex;

ll ghshi(ll hsh){
  if (hshi.count(hsh)) return hshi[hsh];
  hshi[hsh]=++hshindex;
  return hshindex;
}

inline int gli(int c, int w){
  if (!w) return 4;
  if (rt[c][0]==w) return 0;
  if (rt[c][1]==w) return 1;
  if (rt[c][2]==w) return 2;
  if (rt[c][3]==w) return 3;
}

vector<ll> hshm;

ll chsh(int c, int p){
  int li=gli(c, p);
  if (ihsh[c][li]) return hshis[c][li];

  for (int i=0; i<rt[c].size(); ++i){
    if (i==li) continue;
    chsh(rt[c][i], c);
  }
  hshm.clear();
  for (int i=0; i<rt[c].size(); ++i){
    if (i==li) continue;
    hshm.push_back(chsh(rt[c][i], c));
  }
  ihsh[c][li]=1;
  sort(hshm.begin(), hshm.end());
  hshs[c][li]=1;
  for (int i=0; i<hshm.size(); ++i){
    hshs[c][li]+=hshm[i];
    hshs[c][li]*=A;
    hshs[c][li]%=M;
  }
  hshis[c][li]=ghshi(hshs[c][li]);
  return hshis[c][li];
}

int main(){
  cin >> n;
  for (int i=1; i<n; ++i){
    int a, b;
    cin >> a >> b;
    rt[a].push_back(b);
    rt[b].push_back(a);
  }

  for (int i=1; i<=n; ++i){
    if (rt[i].size()<4){
      ls.insert(chsh(i, 0));
    }
  }

  cout << ls.size() << "\n";
}

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <set>
using namespace std;
typedef long long LL;
#define dd c=getchar()
inline int read(){
	int a=0,b=1,dd;
	while(!isdigit(c)){if(c=='-')b=-b;dd;}
	while(isdigit(c)){a=a*10+c-'0';dd;}
	return a*b;
}
#undef dd
const int seed=17,md=1000000009;
int n,ans;
vector<int>e[100003];
set<LL>vis;
LL f[100003];
inline LL s3(LL v){return v*v%md*v%md;}
void calf(int u,int fa){
	f[u]=seed;
	for(int i:e[u]){
		if(i==fa)continue;
		calf(i,u);
		(f[u]+=s3(f[i]))%=md;
	}
}
void cals(int u,int fa){
	if(fa!=-1){
		f[u]+=s3(f[fa]-s3(f[u]));
		f[u]%=md;
		if(f[u]<0)f[u]+=md;
	}
	if(e[u].size()<4&&!vis.count(f[u])){
		vis.insert(f[u]);
		ans++;
	}
	for(int i:e[u]){
		if(i!=fa)cals(i,u);
	}
}
int main(){
	n=read();
	for(int i=1;i<n;i++){
		static int x,y;
		x=read();
		y=read();
		e[x].push_back(y);
		e[y].push_back(x);
	}
	calf(1,-1);
	cals(1,-1);
	printf("%d\n",ans);
	return 0;
}

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
const int N = 1e5, K = 4;
vector<int> g[N], b;
int a[N];
int get_index(const vector<int> x)
{
	static map<vector<int>, int> m;
	static int cnt;
	if (m.find(x) == m.end()) m[x] = cnt++;
	return m[x];
}
void dfs_pre(int u, int fa)
{
	vector<int> x;
	for (int v : g[u])
		if (v != fa)
		{
			dfs_pre(v, u);
			x.push_back(a[v]);
		}
	sort(x.begin(), x.end());
	a[u] = get_index(x);
}
void dfs(int u, int fa)
{
	vector<int> x;
	if (g[u].size() < K)
	{
		for (int v : g[u]) x.push_back(a[v]);
		sort(x.begin(), x.end());
		b.push_back(get_index(x));
	}
	sort(g[u].begin(), g[u].end(), [](int x, int y) { return a[x] < a[y]; });
	x.clear();
	for (int i = 1; i < g[u].size(); i++) x.push_back(a[g[u][i]]);
	for (int i = 0; i < g[u].size(); i++)
	{
		if (i > 0) x[i - 1] = a[g[u][i]];
		if (g[u][i] != fa)
		{
			a[u] = get_index(x);
			dfs(g[u][i], u);
		}
	}
}
int main()
{
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	for (int i = 0; i < n - 1; i++)
	{
		int x, y;
		cin >> x >> y;
		x--, y--;
		g[x].push_back(y);
		g[y].push_back(x);
	}
	dfs_pre(0, -1);
	dfs(0, -1);
	sort(b.begin(), b.end());
	int cnt = 0;
	for (int i = 0; i < b.size(); i++)
		if (i == 0 || b[i] != b[i - 1]) cnt++;
	cout << cnt << endl;
}

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define Q 19260817
#define mod 993729403
#define mod2 806053187
#define Q2 20030113
#define maxn 100001
int head[maxn],nxt[maxn<<2],ver[maxn<<2],tot;int n;int d[maxn];
map<pair<int,int>,int> hash,hash2;
map<int,bool> mp,mp2;
inline int cube(int x){return x*x%mod*x%mod;}
inline int cube2(int x){return x*x%mod2*x%mod2;}
inline void addedge(int a,int b)
{
	nxt[++tot]=head[a];ver[tot]=b;head[a]=tot;d[a]++;
	nxt[++tot]=head[b];ver[tot]=a;head[b]=tot;d[b]++;
}
inline int calc_hash(int x,int fa)
{
	if(hash[make_pair(x,fa)]) return hash[make_pair(x,fa)];
	int res=Q;
	for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa) res=(res+cube(calc_hash(ver[i],x)))%mod;
	hash[make_pair(x,fa)]=res;
	return res;
}
inline int calc_hash2(int x,int fa)
{
	if(hash2[make_pair(x,fa)]) return hash2[make_pair(x,fa)];
	int res=Q2;
	for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa) res=(res+cube2(calc_hash2(ver[i],x)))%mod2;
	hash2[make_pair(x,fa)]=res;
	return res;
}
inline bool calc(int x)
{
	hash[make_pair(0,0)]=hash2[make_pair(0,0)]=0;
	head[0]=0;nxt[++tot]=head[0];ver[tot]=x;head[0]=tot;d[x]++;
	int hhh=calc_hash(0,0),hhh2=calc_hash2(0,0);
	if(mp[hhh]&&mp2[hhh2]) return tot--,d[x]--,0;
	mp[hhh]=mp2[hhh2]=1;
	return tot--,d[x]--,1;
}
inline void init()
{
	scanf("%I64d",&n);
	for(int i=1,a,b;i<n;i++) scanf("%I64d%I64d",&a,&b),addedge(a,b);
}
signed main()
{
	init();
	int res=0;
	for(int i=1;i<=n;i++) if(d[i]<4&&calc(i)) res++;
	cout<<res;
}

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
#include<string>
#define LL long long
using namespace std;
const int MAXN = 100005;
const LL MOD[4] = {199999LL, 30319LL, 123401LL, 1000000007LL};
int n;
int root;
int ans;
vector<int> e[MAXN];
int visited[MAXN];
int size[MAXN];
int weight[MAXN];
LL h[MAXN][4];
LL hash[MAXN][4];
int id[2];
inline void init(){//��ʼ����ϣ��
	for(int i = 1; i <= n + 2; i++){
		h[i][0] = (LL)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD[0];
		h[i][1] = (LL)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD[1];
		h[i][2] = (LL)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD[2];
		h[i][3] = (LL)((double)(MAXN + 1) * rand() / (RAND_MAX + 1.0)) % MOD[3];
	}
}
void dfs(int x){//��һ��dfs���ҳ����ģ�sizeΪ��dfs��������С��weightΪ�����������ָ����󲿷ֵĴ�С��
	visited[x] = true;
	size[x] = 1;
	weight[x] = 0;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		if(!visited[y]){
			dfs(y);
			size[x] += size[y];
			weight[x] = max(size[y], weight[x]);
		}
	}
	if(n - size[x] > weight[x]) weight[x] = n - size[x];
}
void add_edge(int x, int y){
	e[x].push_back(y);
	e[y].push_back(x);
}
void dfs2(int x, int ht){//�ڶ���dfs��������Ϊ���������������hashֵ��htΪ�ڵ����
	visited[x] = true;
	hash[x][0] = hash[x][1] = hash[x][2] = hash[x][3] = 1LL;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		if(!visited[y]){
			dfs2(y, ht + 1);
			hash[x][0] += hash[y][0];
			hash[x][1] += hash[y][1];
			hash[x][2] += hash[y][2];
			hash[x][3] += hash[y][3];
		}
	}
	hash[x][0] = (hash[x][0] * h[ht][0]) % MOD[0];
	hash[x][1] = (hash[x][1] * h[ht][1]) % MOD[1];
	hash[x][2] = (hash[x][2] * h[ht][2]) % MOD[2];
	hash[x][3] = (hash[x][3] * h[ht][3]) % MOD[3];
}
void dfs3(int x, int ht){//������dfs������answer��htΪ�ڵ���ȣ�ͬ��������ֻ��������һ����
	LL s[4][4], cnt = 0, ok;
	visited[x] = true;
	for(int i = 0; i < e[x].size(); i++){
		int y = e[x][i];
		ok = 1;
		if(visited[y])continue;
		for(int j = 0; j < cnt; j++)
		if(hash[y][0] == s[j][0] && hash[y][1] == s[j][1] && hash[y][2] == s[j][2] && hash[y][3] == s[j][3]){//����
			ok = 0;
			break;
		}
		if(!ok)continue;
		s[cnt][0] = hash[y][0];
		s[cnt][1] = hash[y][1];
		s[cnt][2] = hash[y][2];
		s[cnt][3] = hash[y][3];
		cnt++;
		dfs3(y, ht + 1);
	}
	if(e[x].size() < 4) ans++;//����ɼӣ�+1s
}
int main(){
	srand((int)time(0));
	scanf("%d", &n);
	init();
	for(int i = 1; i < n; i++){//��ͼ
		int x, y;
		scanf("%d%d", &x, &y);
		add_edge(x, y);
	}
	dfs(1);
	for(int i = 1; i <= n; i++){//�ҳ�����
		if(weight[i] <= n / 2){
			id[1] = id[0];
			id[0] = i;
		}
	}
	if(id[1]){//����������ġ�������ô�������м��һ������Ϊ��������answer��ȻҪ������������1s
		ans = -1;
		add_edge(n + 1, id[0]);
		add_edge(n + 1, id[1]);
		vector<int> ::iterator Iter;
		Iter = find(e[id[0]].begin(), e[id[0]].end(), id[1]);
		if(Iter == e[id[0]].end()){
			printf("-1\n");
			return 0;
		}
		e[id[0]].erase(Iter);
		Iter = find(e[id[1]].begin(), e[id[1]].end(), id[0]);
		if(Iter == e[id[1]].end()){
			printf("-1\n");
			return 0;
		}
		e[id[1]].erase(Iter);
		root = ++n;
	}
	else root = id[0];
	memset(visited, 0, sizeof(visited));
	dfs2(root, 1);
	memset(visited, 0, sizeof(visited));
	dfs3(root, 1);
	printf("%d\n", ans);
	return 0;
}

#ifndef __clang__
#pragma GCC optimize ("-O3")
#endif
#ifdef ONLINE_JUDGE
#define NDEBUG 1
#endif
#define _GLIBCXX_USE_CXX11_ABI 0
#include <stdio.h>
#include <bits/stdc++.h>

#define DESTRUCT2(p, a, b)                      \
  auto a = get<0>(p);                           \
  auto b = get<1>(p);

#define DESTRUCT3(p, a, b, c)                   \
  auto a = get<0>(p);                           \
  auto b = get<1>(p);                           \
  auto c = get<2>(p);

#define DESTRUCT4(p, a, b, c, d)                \
  auto a = get<0>(p);                           \
  auto b = get<1>(p);                           \
  auto c = get<2>(p);                           \
  auto d = get<3>(p);

#define FOR(i, n)     for(lli i = 0; i < (lli)(n); ++i)
#define FORU(i, j, k) for(lli i = (j); i <= (lli)(k); ++i)
#define FORD(i, j, k) for(lli i = (j); i >= (lli)(k); --i)

#define SQ(x) ((x)*(x))

#define all(x) begin(x), end(x)
#define rall(x) rbegin(x), rend(x)
#define mp make_pair
#define mt make_tuple
#define pb push_back
#define eb emplace_back

using namespace std;

template<typename... As>
struct tpl : public std::tuple<As...> {
  using std::tuple<As...>::tuple;

  template<typename T = tuple<As...> >
  typename tuple_element<0, T>::type const&
  x() const { return get<0>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<0, T>::type&
  x() { return get<0>(*this); }

  template<typename T = tuple<As...> >
  typename tuple_element<1, T>::type const&
  y() const { return get<1>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<1, T>::type&
  y() { return get<1>(*this); }

  template<typename T = tuple<As...> >
  typename tuple_element<2, T>::type const&
  z() const { return get<2>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<2, T>::type&
  z() { return get<2>(*this); }

  template<typename T = tuple<As...> >
  typename tuple_element<3, T>::type const&
  w() const { return get<3>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<3, T>::type&
  w() { return get<3>(*this); }
};

using lli   = long long int;
using llu   = long long unsigned;

using pii   = tpl<lli, lli>;
using piii  = tpl<lli, lli, lli>;
using piiii = tpl<lli, lli, lli, lli>;
using vi    = vector<lli>;
using vii   = vector<pii>;
using viii  = vector<piii>;
using vvi   = vector<vi>;
using vvii  = vector<vii>;
using vviii = vector<viii>;

template<class T>
using min_queue = priority_queue<T, vector<T>, greater<T> >;
template<class T>
using max_queue = priority_queue<T>;

template<size_t... I>
struct my_index_sequence {
  using type = my_index_sequence;
  static constexpr array<size_t, sizeof...(I)> value = { {I}... };
};

namespace my_index_sequence_detail {
  template<typename I, typename J> struct concat;
  template<size_t... I, size_t... J>
  struct concat<my_index_sequence<I...>, my_index_sequence<J...> > :
    my_index_sequence<I..., (sizeof...(I)+J)...> { };
  template<size_t N> struct make_index_sequence :
    concat<typename make_index_sequence<N/2>::type, typename make_index_sequence<N-N/2>::type>::type { };
  template <> struct make_index_sequence<0> : my_index_sequence<>{};
  template <> struct make_index_sequence<1> : my_index_sequence<0>{};
}

template<class... A>
using my_index_sequence_for = typename my_index_sequence_detail::make_index_sequence<sizeof...(A)>::type;

template<class T, size_t... I>
void print_tuple(ostream& s, T const& a, my_index_sequence<I...>){
  using swallow = int[];
  (void)swallow{0, (void(s << (I == 0? "" : ", ") << get<I>(a)), 0)...};
}

template<class T>
ostream& print_collection(ostream& s, T const& a){
  s << '[';
  for(auto it = begin(a); it != end(a); ++it){
    s << *it;
    if(it != prev(end(a))) s << " ";
  }
  return s << ']';
}

template<class... A>
ostream& operator<<(ostream& s, tpl<A...> const& a){
  s << '(';
  print_tuple(s, a, my_index_sequence_for<A...>{});
  return s << ')';
}

template<class... A>
ostream& operator<<(ostream& s, tuple<A...> const& a){
  s << '(';
  print_tuple(s, a, my_index_sequence_for<A...>{});
  return s << ')';
}

template<class A, class B>
ostream& operator<<(ostream& s, pair<A, B> const& a){
  return s << "(" << get<0>(a) << ", " << get<1>(a) << ")";
}

template<class T, size_t I>
ostream& operator<<(ostream& s, array<T, I> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, vector<T> const& a) { return print_collection(s, a); }
template<class T, class U>
ostream& operator<<(ostream& s, multimap<T, U> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, multiset<T> const& a) { return print_collection(s, a); }
template<class T, class U>
ostream& operator<<(ostream& s, map<T, U> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, set<T> const& a) { return print_collection(s, a); }

namespace std {
  namespace {
    template <class T>
    inline void hash_combine(size_t& seed, T const& v) {
      seed ^= hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
    }
    template <class Tuple, size_t Index = tuple_size<Tuple>::value - 1>
    struct HashValueImpl {
      static void apply(size_t& seed, Tuple const& tuple) {
        HashValueImpl<Tuple, Index-1>::apply(seed, tuple);
        hash_combine(seed, get<Index>(tuple));
      }
    };
    template <class Tuple>
    struct HashValueImpl<Tuple, 0> {
      static void apply(size_t& seed, Tuple const& tuple) {
        hash_combine(seed, get<0>(tuple));
      }
    };
  }
  template <typename ... TT>
  struct hash<tuple<TT...>> {
    size_t operator()(tuple<TT...> const& tt) const {
      size_t seed = 0;
      HashValueImpl<tuple<TT...> >::apply(seed, tt);
      return seed;
    }
  };
  template <typename ... TT>
  struct hash<tpl<TT...>> {
    size_t operator()(tpl<TT...> const& tt) const {
      size_t seed = 0;
      HashValueImpl<tuple<TT...> >::apply(seed, tt);
      return seed;
    }
  };
}

int read_positive(){
  char c; int x=0;
  do { c = getchar(); } while(c<'0' || c>'9');
  while(c>='0'&&c<='9') {
    x=10*x+(c-'0');
    c = getchar();
  }
  return x;
}

//------------------------------------------------------------------------------

// --- BEGIN SNIPPET TREE ---

struct treechain {
  lli root = -1;
  lli size = 0;
  vi  nodes;

  treechain() { }

#ifdef WITH_HLD
  using segment = segment_tree; // segment tree / bit / other
  segment A;
  void build(){ A = segment(size); /* make segment tree */ }
#else
  void build(){ }
#endif
};

struct tree {
  lli n;
  vvi G;

  vi parent;
  vi depth;
  vi size;
  vi order, rorder;
  vii eorder;

  vector<treechain> chains;
  vector<lli>       chain;
  vector<lli>       chainIx;

  tree(lli n_) : n(n_), G(n) { }

  void read_graph(istream& input = cin) {
    FOR(i, n-1) {
      lli u, v; input >> u >> v;
      u -= 1; v -= 1;
      G[u].pb(v); G[v].pb(u);
    }
  }

  void calcparent() {
    if(parent.empty()) {
      parent.assign(n, -1);
      order.clear();
      vi E(n, 0);
      vector<lli> Q; Q.pb(0);
      while(!Q.empty()) {
        lli i = Q.back(); Q.pop_back();
        order.pb(i);
        E[i] = 1;
        for(auto j : G[i]) if(!E[j]) {
            parent[j] = i;
            Q.pb(j);
          }
      }
      rorder = order;
      reverse(all(rorder));
    }
  }

  template<typename T>
  inline vector<vector<T> > makeEVec(T const& def = T()) {
    vector<vector<T> > v(n); FOR(i, n) v[i].assign(G[i].size(), def);
    return v;
  }

  void calceorder() {
    if(eorder.empty()) {
      vvi E = makeEVec(0ll);
      FOR(i, n) FOR(j_, G[i].size()) if(!E[i][j_]) {
        vii Q; Q.pb(mt(i,j_));
        vii tmp;
        while(!Q.empty()) {
          DESTRUCT2(Q.back(), i, j_); Q.pop_back();
          tmp.pb(mt(i, j_)); E[i][j_] = 1;
          lli j = G[i][j_];
          FOR(k_, G[j].size()) if(G[j][k_] != i && !E[j][k_]) Q.pb(mt(j, k_));
        }
        reverse(all(tmp));
        eorder.insert(end(eorder), all(tmp));
      }
    }
  }

  void calcsize() {
    calcparent();
    if(size.empty()) {
      size.assign(n, 1);
      for(auto i : rorder) if(parent[i]!=-1) size[parent[i]] += size[i];
    }
  }

  void calcdepth() {
    calcparent();
    if(depth.empty()) {
      depth.assign(n, 0);
      for(auto i : order) if(parent[i] != -1) depth[i] = depth[parent[i]] + 1;
    }
  }

  void calchld() {
    if(chains.empty()){
      calcsize();
      calcdepth();

      chain.assign(n, -1);
      for(auto i : rorder) {
        lli best = -1;
        for(auto j : G[i]) if(j != parent[i]) {
            if(best == -1 || size[j] > size[best]) best = j;
          }
        if(best == -1) {
          chain[i] = chains.size();
          chains.eb();
        }else{
          chain[i] = chain[best];
        }
        chains[chain[i]].size += 1;
      }

      chainIx.assign(n, -1);
      for(auto i : order) {
        if(parent[i]==-1 || chain[i] != chain[parent[i]]) chains[chain[i]].root = i;
        chainIx[i] = chains[chain[i]].nodes.size();
        chains[chain[i]].nodes.pb(i);
      };

      for(auto& c : chains) c.build();
    }
  }

  // O(log n) lca
  lli lca(lli a, lli b) {
    calchld();
    while(chain[a] != chain[b]) {
      if(depth[chains[chain[a]].root]>depth[chains[chain[b]].root]) {
        a = parent[chains[chain[a]].root];
      }else{
        b = parent[chains[chain[b]].root];
      }
    }
    if(depth[a]<depth[b]) return a; else return b;
  }

  lli dist(lli a, lli b) {
    calchld();
    return depth[a]+depth[b]-2*depth[lca(a, b)];
  }

#ifdef WITH_HLD
  // arguments to f :
  // segment, segment range, range in path from a to b (a = 0, b = dist(a, b))
  // the segment range is increasing
  // the range in path can be decreasing
  // O (log² n)
  void hld_query(lli a, lli b, function<void(treechain::segment&, lli, lli, lli, lli)> f) {
    calchld();
    lli from = 0, to = dist(a, b);
    while(chain[a] != chain[b]) {
      if(depth[chains[chain[a]].root]>depth[chains[chain[b]].root]) {
        lli a_ = parent[chains[chain[a]].root];
        lli d = depth[a]-depth[a_];
        f(chains[chain[a]].A, 0, chainIx[a], from+d, from);
        from += d;
        a = a_;
      }else{
        lli b_ = parent[chains[chain[b]].root];
        lli d = depth[b]-depth[b_];
        f(chains[chain[b]].A, 0, chainIx[b], to-d, to);
        to -= d;
        b = b_;
      }
    }
    if(depth[a]<depth[b]) {
      f(chains[chain[a]].A, chainIx[a]+1, chainIx[b], from, to);
    }else{
      f(chains[chain[a]].A, chainIx[b]+1, chainIx[a], from, to);
    }
  }
#endif
};

// --- END SNIPPET TREE ---

int main(int, char**){
  ios::sync_with_stdio(0); cin.tie(0);
  int n; cin >> n;
  tree t(n); t.read_graph();
  t.calceorder();
  auto v = t.makeEVec<size_t>();
  for(auto p : t.eorder) {
    DESTRUCT2(p, i, j_); int j = t.G[i][j_];
    v[i][j_] = 0x9e3779b9;
    FOR(k_, t.G[j].size()) {
      int k = t.G[j][k_];
      if(k == i) continue;
      v[i][j_] *= SQ(v[j][k_]);
    }
  }
  lli count = 0;
  set<size_t> S;
  FOR(i, n) if(t.G[i].size() < 4) {
    count += 1;
    size_t h = 0x9e3779b9;
    FOR(j_, t.G[i].size()) {
      h *= SQ(v[i][j_]);
    }
    S.insert(h);
  }
  cout << S.size() << endl;
  return 0;
}

#ifndef __clang__
#pragma GCC optimize ("-O3")
#endif
#ifdef ONLINE_JUDGE
#define NDEBUG 1
#endif
#define _GLIBCXX_USE_CXX11_ABI 0
#include <stdio.h>
#include <bits/stdc++.h>

#define DESTRUCT2(p, a, b)                      \
  auto a = get<0>(p);                           \
  auto b = get<1>(p);

#define DESTRUCT3(p, a, b, c)                   \
  auto a = get<0>(p);                           \
  auto b = get<1>(p);                           \
  auto c = get<2>(p);

#define DESTRUCT4(p, a, b, c, d)                \
  auto a = get<0>(p);                           \
  auto b = get<1>(p);                           \
  auto c = get<2>(p);                           \
  auto d = get<3>(p);

#define FOR(i, n)     for(lli i = 0; i < (lli)(n); ++i)
#define FORU(i, j, k) for(lli i = (j); i <= (lli)(k); ++i)
#define FORD(i, j, k) for(lli i = (j); i >= (lli)(k); --i)

#define SQ(x) ((x)*(x))

#define all(x) begin(x), end(x)
#define rall(x) rbegin(x), rend(x)
#define mp make_pair
#define mt make_tuple
#define pb push_back
#define eb emplace_back

using namespace std;

template<typename... As>
struct tpl : public std::tuple<As...> {
  using std::tuple<As...>::tuple;

  template<typename T = tuple<As...> >
  typename tuple_element<0, T>::type const&
  x() const { return get<0>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<0, T>::type&
  x() { return get<0>(*this); }

  template<typename T = tuple<As...> >
  typename tuple_element<1, T>::type const&
  y() const { return get<1>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<1, T>::type&
  y() { return get<1>(*this); }

  template<typename T = tuple<As...> >
  typename tuple_element<2, T>::type const&
  z() const { return get<2>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<2, T>::type&
  z() { return get<2>(*this); }

  template<typename T = tuple<As...> >
  typename tuple_element<3, T>::type const&
  w() const { return get<3>(*this); }
  template<typename T = tuple<As...> >
  typename tuple_element<3, T>::type&
  w() { return get<3>(*this); }
};

using lli   = long long int;
using llu   = long long unsigned;

using pii   = tpl<lli, lli>;
using piii  = tpl<lli, lli, lli>;
using piiii = tpl<lli, lli, lli, lli>;
using vi    = vector<lli>;
using vii   = vector<pii>;
using viii  = vector<piii>;
using vvi   = vector<vi>;
using vvii  = vector<vii>;
using vviii = vector<viii>;

template<class T>
using min_queue = priority_queue<T, vector<T>, greater<T> >;
template<class T>
using max_queue = priority_queue<T>;

template<size_t... I>
struct my_index_sequence {
  using type = my_index_sequence;
  static constexpr array<size_t, sizeof...(I)> value = { {I}... };
};

namespace my_index_sequence_detail {
  template<typename I, typename J> struct concat;
  template<size_t... I, size_t... J>
  struct concat<my_index_sequence<I...>, my_index_sequence<J...> > :
    my_index_sequence<I..., (sizeof...(I)+J)...> { };
  template<size_t N> struct make_index_sequence :
    concat<typename make_index_sequence<N/2>::type, typename make_index_sequence<N-N/2>::type>::type { };
  template <> struct make_index_sequence<0> : my_index_sequence<>{};
  template <> struct make_index_sequence<1> : my_index_sequence<0>{};
}

template<class... A>
using my_index_sequence_for = typename my_index_sequence_detail::make_index_sequence<sizeof...(A)>::type;

template<class T, size_t... I>
void print_tuple(ostream& s, T const& a, my_index_sequence<I...>){
  using swallow = int[];
  (void)swallow{0, (void(s << (I == 0? "" : ", ") << get<I>(a)), 0)...};
}

template<class T>
ostream& print_collection(ostream& s, T const& a){
  s << '[';
  for(auto it = begin(a); it != end(a); ++it){
    s << *it;
    if(it != prev(end(a))) s << " ";
  }
  return s << ']';
}

template<class... A>
ostream& operator<<(ostream& s, tpl<A...> const& a){
  s << '(';
  print_tuple(s, a, my_index_sequence_for<A...>{});
  return s << ')';
}

template<class... A>
ostream& operator<<(ostream& s, tuple<A...> const& a){
  s << '(';
  print_tuple(s, a, my_index_sequence_for<A...>{});
  return s << ')';
}

template<class A, class B>
ostream& operator<<(ostream& s, pair<A, B> const& a){
  return s << "(" << get<0>(a) << ", " << get<1>(a) << ")";
}

template<class T, size_t I>
ostream& operator<<(ostream& s, array<T, I> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, vector<T> const& a) { return print_collection(s, a); }
template<class T, class U>
ostream& operator<<(ostream& s, multimap<T, U> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, multiset<T> const& a) { return print_collection(s, a); }
template<class T, class U>
ostream& operator<<(ostream& s, map<T, U> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, set<T> const& a) { return print_collection(s, a); }

namespace std {
  namespace {
    template <class T>
    inline void hash_combine(size_t& seed, T const& v) {
      seed ^= hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
    }
    template <class Tuple, size_t Index = tuple_size<Tuple>::value - 1>
    struct HashValueImpl {
      static void apply(size_t& seed, Tuple const& tuple) {
        HashValueImpl<Tuple, Index-1>::apply(seed, tuple);
        hash_combine(seed, get<Index>(tuple));
      }
    };
    template <class Tuple>
    struct HashValueImpl<Tuple, 0> {
      static void apply(size_t& seed, Tuple const& tuple) {
        hash_combine(seed, get<0>(tuple));
      }
    };
  }
  template <typename ... TT>
  struct hash<tuple<TT...>> {
    size_t operator()(tuple<TT...> const& tt) const {
      size_t seed = 0;
      HashValueImpl<tuple<TT...> >::apply(seed, tt);
      return seed;
    }
  };
  template <typename ... TT>
  struct hash<tpl<TT...>> {
    size_t operator()(tpl<TT...> const& tt) const {
      size_t seed = 0;
      HashValueImpl<tuple<TT...> >::apply(seed, tt);
      return seed;
    }
  };
}

int read_positive(){
  char c; int x=0;
  do { c = getchar(); } while(c<'0' || c>'9');
  while(c>='0'&&c<='9') {
    x=10*x+(c-'0');
    c = getchar();
  }
  return x;
}

//------------------------------------------------------------------------------

// --- BEGIN SNIPPET TREE ---

struct treechain {
  lli root = -1;
  lli size = 0;
  vi  nodes;

  treechain() { }

#ifdef WITH_HLD
  using segment = segment_tree; // segment tree / bit / other
  segment A;
  void build(){ A = segment(size); /* make segment tree */ }
#else
  void build(){ }
#endif
};

struct tree {
  lli n;
  vvi G;

  vi parent;
  vi depth;
  vi size;
  vi order, rorder;
  vii eorder;

  vector<treechain> chains;
  vector<lli>       chain;
  vector<lli>       chainIx;

  tree(lli n_) : n(n_), G(n) { }

  void read_graph(istream& input = cin) {
    FOR(i, n-1) {
      lli u, v; input >> u >> v;
      u -= 1; v -= 1;
      G[u].pb(v); G[v].pb(u);
    }
  }

  void calcparent() {
    if(parent.empty()) {
      parent.assign(n, -1);
      order.clear();
      vi E(n, 0);
      vector<lli> Q; Q.pb(0);
      while(!Q.empty()) {
        lli i = Q.back(); Q.pop_back();
        order.pb(i);
        E[i] = 1;
        for(auto j : G[i]) if(!E[j]) {
            parent[j] = i;
            Q.pb(j);
          }
      }
      rorder = order;
      reverse(all(rorder));
    }
  }

  template<typename T>
  inline vector<vector<T> > makeEVec(T const& def = T()) {
    vector<vector<T> > v(n); FOR(i, n) v[i].assign(G[i].size(), def);
    return v;
  }

  void calceorder() {
    if(eorder.empty()) {
      vvi E = makeEVec(0ll);
      FOR(i, n) FOR(j_, G[i].size()) if(!E[i][j_]) {
        vii Q; Q.pb(mt(i,j_));
        vii tmp;
        while(!Q.empty()) {
          DESTRUCT2(Q.back(), i, j_); Q.pop_back();
          tmp.pb(mt(i, j_)); E[i][j_] = 1;
          lli j = G[i][j_];
          FOR(k_, G[j].size()) if(G[j][k_] != i && !E[j][k_]) Q.pb(mt(j, k_));
        }
        reverse(all(tmp));
        eorder.insert(end(eorder), all(tmp));
      }
    }
  }

  void calcsize() {
    calcparent();
    if(size.empty()) {
      size.assign(n, 1);
      for(auto i : rorder) if(parent[i]!=-1) size[parent[i]] += size[i];
    }
  }

  void calcdepth() {
    calcparent();
    if(depth.empty()) {
      depth.assign(n, 0);
      for(auto i : order) if(parent[i] != -1) depth[i] = depth[parent[i]] + 1;
    }
  }

  void calchld() {
    if(chains.empty()){
      calcsize();
      calcdepth();

      chain.assign(n, -1);
      for(auto i : rorder) {
        lli best = -1;
        for(auto j : G[i]) if(j != parent[i]) {
            if(best == -1 || size[j] > size[best]) best = j;
          }
        if(best == -1) {
          chain[i] = chains.size();
          chains.eb();
        }else{
          chain[i] = chain[best];
        }
        chains[chain[i]].size += 1;
      }

      chainIx.assign(n, -1);
      for(auto i : order) {
        if(parent[i]==-1 || chain[i] != chain[parent[i]]) chains[chain[i]].root = i;
        chainIx[i] = chains[chain[i]].nodes.size();
        chains[chain[i]].nodes.pb(i);
      };

      for(auto& c : chains) c.build();
    }
  }

  // O(log n) lca
  lli lca(lli a, lli b) {
    calchld();
    while(chain[a] != chain[b]) {
      if(depth[chains[chain[a]].root]>depth[chains[chain[b]].root]) {
        a = parent[chains[chain[a]].root];
      }else{
        b = parent[chains[chain[b]].root];
      }
    }
    if(depth[a]<depth[b]) return a; else return b;
  }

  lli dist(lli a, lli b) {
    calchld();
    return depth[a]+depth[b]-2*depth[lca(a, b)];
  }

#ifdef WITH_HLD
  // arguments to f :
  // segment, segment range, range in path from a to b (a = 0, b = dist(a, b))
  // the segment range is increasing
  // the range in path can be decreasing
  // O (log² n)
  void hld_query(lli a, lli b, function<void(treechain::segment&, lli, lli, lli, lli)> f) {
    calchld();
    lli from = 0, to = dist(a, b);
    while(chain[a] != chain[b]) {
      if(depth[chains[chain[a]].root]>depth[chains[chain[b]].root]) {
        lli a_ = parent[chains[chain[a]].root];
        lli d = depth[a]-depth[a_];
        f(chains[chain[a]].A, 0, chainIx[a], from+d, from);
        from += d;
        a = a_;
      }else{
        lli b_ = parent[chains[chain[b]].root];
        lli d = depth[b]-depth[b_];
        f(chains[chain[b]].A, 0, chainIx[b], to-d, to);
        to -= d;
        b = b_;
      }
    }
    if(depth[a]<depth[b]) {
      f(chains[chain[a]].A, chainIx[a]+1, chainIx[b], from, to);
    }else{
      f(chains[chain[a]].A, chainIx[b]+1, chainIx[a], from, to);
    }
  }
#endif
};

// --- END SNIPPET TREE ---

int main(int, char**){
  ios::sync_with_stdio(0); cin.tie(0);
  int n; cin >> n;
  tree t(n); t.read_graph();
  t.calceorder();
  auto v = t.makeEVec<size_t>();
  for(auto p : t.eorder) {
    DESTRUCT2(p, i, j_); int j = t.G[i][j_];
    v[i][j_] = 0;
    FOR(k_, t.G[j].size()) {
      int k = t.G[j][k_];
      if(k == i) continue;
      v[i][j_] += SQ(0x9e3779b9^v[j][k_]);
    }
  }
  lli count = 0;
  set<size_t> S;
  FOR(i, n) if(t.G[i].size() < 4) {
    count += 1;
    size_t h = 0;
    FOR(j_, t.G[i].size()) {
      h += SQ(0x9e3779b9^v[i][j_]);
    }
    S.insert(h);
  }
  cout << S.size() << endl;
  return 0;
}

#include<cstdio>
#include<set>
#include<vector>
#include<map>
#include<algorithm>
#define it register int
#define il inline
using namespace std;
typedef unsigned long long ll;
const int N=1000005;
int h[N],nxt[N],adj[N],t,n,u,v,d[N],cnt;
set<ll> S;
map<ll,map<ll,ll> > f;
map<vector<ll>,int> mp;
il ll dfs(it x,it fa){
	if(f[x][fa]) return f[x][fa];
	vector<ll> g;g.clear();
	//ll val=1;
	for(it i=h[x];i;i=nxt[i])
		if(adj[i]!=fa) g.push_back(dfs(adj[i],x));
	std::sort(g.begin(),g.end());
	//for(it i=0,sz=g.size();i<sz;++i) val=(val*137+g[i]*23333)*823%998244353*19260817;
	if(!mp[g]) mp[g]=++cnt;
	return f[x][fa]=cnt;
}
il void add(){
	nxt[++t]=h[u],h[u]=t,adj[t]=v,nxt[++t]=h[v],h[v]=t,adj[t]=u;
}
il void fr(int &num){
    num=0;char c=getchar();int p=1;
    while(c<'0'||c>'9') c=='-'?p=-1,c=getchar():c=getchar();
    while(c>='0'&&c<='9') num=num*10+c-'0',c=getchar();
    num*=p;
}
int main(){
	fr(n);
	for(it i=1;i<n;++i) fr(u),fr(v),add(),++d[u],++d[v];
	for(it i=1;i<=n;++i)
		if(d[i]<4) S.insert(dfs(i,-1));
	printf("%d",S.size());
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
const int N=1e6+5;
int n,du[N],size[N],rd[N],val[N];
map<int,int>mp1[N],mp2[N];
vector<int>g[N];
set<int>s;
/*char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}*/
#define gc getchar
inline int read()
{
	int ret=0,f=0;char c=gc();
	while(!isdigit(c)){if(c=='-')f=1;c=gc();}
	while(isdigit(c)){ret=ret*10+c-48;c=gc();}
	if(f)return -ret;return ret;
}
int dfs(int u,int fa)
{
	val[u]=1;
	size[u]=1;
	for(int i=0;i<g[u].size();i++)
	{
		int v=g[u][i];
		if(v==fa)continue;
		if(mp1[v].count(u))
		{
			int x=mp2[v][u];
			val[u]+=mp1[v][u]*rd[x];
			size[u]+=x;
		}
		else{
			val[u]+=dfs(v,u)*rd[size[v]];
			size[u]+=size[v];
		}
	}
	val[u]=val[u]*size[u];
	mp1[u][fa]=val[u];
	mp2[u][fa]=size[u];
	return val[u];
}
signed main()
{
	srand(19260817);
	n=read();
	for(int i=1;i<=n;i++)rd[i]=rand()%100000+1;
	for(int i=1;i<n;i++)
	{
		int x=read(),y=read();
		du[x]++;du[y]++;
		g[x].push_back(y);
		g[y].push_back(x);
	}
	int ans=0;
	for(int i=1;i<=n;i++)
		if(du[i]<(int)4)
			s.insert(dfs(i,0));
	cout<<s.size();
	return 0;
}

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
const int N = 1e5, K = 4;
vector<int> g[N], b;
int a[N];
int get_index(const vector<int> x)
{
	static map<vector<int>, int> m;
	static int cnt;
	if (m.find(x) == m.end()) m[x] = cnt++;
	return m[x];
}
void dfs_pre(int u, int fa)
{
	vector<int> x;
	for (int v : g[u])
		if (v != fa)
		{
			dfs_pre(v, u);
			x.push_back(a[v]);
		}
	sort(x.begin(), x.end());
	a[u] = get_index(x);
}
void dfs(int u, int fa)
{
	vector<int> x;
	if (g[u].size() < K)
	{
		for (int v : g[u])
			if (v != fa) x.push_back(a[v]);
		sort(x.begin(), x.end());
		b.push_back(get_index(x));
	}
	sort(g[u].begin(), g[u].end(), [](int x, int y) { return a[x] < a[y]; });
	x.clear();
	for (int i = 1; i < g[u].size(); i++) x.push_back(a[g[u][i]]);
	for (int i = 0; i < g[u].size(); i++)
	{
		if (i > 0) x[i - 1] = a[g[u][i]];
		if (g[u][i] != fa)
		{
			a[g[u][i]] = get_index(x);
			dfs(g[u][i], u);
		}
	}
}
int main()
{
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	for (int i = 0; i < n - 1; i++)
	{
		int x, y;
		cin >> x >> y;
		x--, y--;
		g[x].push_back(y);
		g[y].push_back(x);
	}
	dfs_pre(0, -1);
	dfs(0, -1);
	sort(b.begin(), b.end());
	int cnt = 0;
	for (int i = 0; i < b.size(); i++)
		if (i == 0 || b[i] != b[i - 1]) cnt++;
	cout << cnt << endl;
}

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXSIZE=30000020;
const int mod=1000000009,base=19260817;
int bufpos;
char buf[MAXSIZE];
#define NEG 0
void init(){
	#ifdef LOCAL
		freopen("718D.txt","r",stdin);
	#endif
	buf[fread(buf,1,MAXSIZE,stdin)]='\0';
	bufpos=0;
}
#if NEG
int readint(){
	bool isneg;
	int val=0;
	for(;!isdigit(buf[bufpos]) && buf[bufpos]!='-';bufpos++);
	bufpos+=(isneg=buf[bufpos]=='-');
	for(;isdigit(buf[bufpos]);bufpos++)
		val=val*10+buf[bufpos]-'0';
	return isneg?-val:val;
}
#else
int readint(){
	int val=0;
	for(;!isdigit(buf[bufpos]);bufpos++);
	for(;isdigit(buf[bufpos]);bufpos++)
		val=val*10+buf[bufpos]-'0';
	return val;
}
#endif
char readchar(){
	for(;isspace(buf[bufpos]);bufpos++);
	return buf[bufpos++];
}
int readstr(char* s){
	int cur=0;
	for(;isspace(buf[bufpos]);bufpos++);
	for(;!isspace(buf[bufpos]);bufpos++)
		s[cur++]=buf[bufpos];
	s[cur]='\0';
	return cur;
}
const int maxn=100002;
map<int,ll> mp[maxn];
vector<int> g[maxn];
int deg[maxn];
ll dfs(int u,int fa){
	map<int,ll>::iterator it=mp[u].find(fa);
	//fprintf(stderr,"on %d %d\n",u,fa);
	//system("pause");
	if (it!=mp[u].end())
		return it->second;
	ll res=base;
	for(auto v:g[u]){
		if (v==fa)
			continue;
		ll t=dfs(v,u);
		res=(res+t*t%mod*t)%mod;
	}
	return mp[u][fa]=res;
}
ll ans[maxn];
int main(){
	init();
	int n=readint();
	for(int i=1;i<n;i++){
		int u=readint(),v=readint();
		g[u].push_back(v);
		g[v].push_back(u);
		deg[u]++;
		deg[v]++;
	}
	int cur=0;
	//puts("WTF");
	dfs(3,0);
	for(int i=1;i<=n;i++)
		if (deg[i]<4)
			ans[++cur]=dfs(i,0);
	sort(ans+1,ans+cur+1);
	printf("%d\n",unique(ans+1,ans+cur+1)-ans-1);
}

#include <bits/stdc++.h>
#define forinc(i,a,b) for(int i = a, _key = b; i <= _key; ++i)
#define fordec(i,a,b) for(int i = a, _key = b; i >= _key; --i)
#define fori(i,n) for(int i = 0, _key = n; i < _key; ++i)
#define ford(i,n) for(int i = n - 1; i >= 0; --i)
#define forvct(i,v) for(int i = 0, _key = v.size(); i < _key; ++i)
#define sqr(x) ((ll)x) * (x)
#define task "x"
#define st first
#define nd second
#define m_p make_pair
#define m_t make_tuple
#define p_b push_back
#define p_f push_front
#define pp_b pop_back
#define pp_f pop_front
#define sn string::npos
#define heap priority_queue
#define ll long long
#define db double
#define str string
#define nn 100010

using namespace std;

const int oo = 1000000007;
const int base = 100003;

int n, res, pp[nn], child[nn];
ll f[nn], g[nn];
vector<int> adj[nn];
vector<pair<ll,pair<int,int> > > a[nn];
map<ll,bool> mark;

void enter()
{
    cin >> n;
    pp[0] = 1;
    pp[1] = base;
    forinc(i,2,n)
    {
        pp[i] = pp[i-1] * base;
        int u, v;
        cin >> u >> v;
        adj[u].p_b(v);
        adj[v].p_b(u);
    }
}

void visit1(const int &u, const int &p)
{
    child[u] = 1;
    forvct(j,adj[u])
    {
        int v = adj[u][j];
        if (v == p) continue;
        visit1(v,u);
        child[u] += child[v];
        a[u].p_b(m_p(f[v],m_p(v,child[v])));
        sort(a[u].begin(),a[u].end());
    }
    f[u] = child[u];
    forvct(i,a[u]) f[u] = f[u] * pp[a[u][i].nd.nd] + a[u][i].st;
}

void visit2(const int &u, const int &p)
{
    if (p)
    {
        int x = n - child[u];
        if (p == 1 && adj[1].size() == 1) x = 1;
        forvct(i,a[p])
            if (a[p][i].nd.st != u) x = x * pp[a[p][i].nd.nd] + a[p][i].st;
        a[u].p_b(m_p(x,m_p(p,n-child[u])));
        sort(a[u].begin(),a[u].end());
    }
    g[u] = n;
    forvct(i,a[u]) g[u] = g[u] * pp[a[u][i].nd.nd] + a[u][i].st;
    if (adj[u].size() < 4 && mark.find(g[u]) == mark.end())
    {
        mark[g[u]] = true;
        res++;
    }
    forvct(j,adj[u])
    {
        int v = adj[u][j];
        if (v == p) continue;
        visit2(v,u);
    }
}

void process()
{
    visit1(1,0);
    visit2(1,0);
    cout << res;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    //srand(time(NULL));
    //freopen(task".inp","r",stdin);
    //freopen(task".out","w",stdout);
    enter();
    process();
}

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>

using namespace std;

#define mp make_pair
#define pb push_back
#define ll long long

#define maxN 100011
#define mod 1000000007
#define base 31

int n, i, x, y;
vector<int> list[maxN];
ll dp[maxN];
vector<ll> sol;

ll compute(int node, int deny) {
    static ll ans;
    static vector<int> aux;

    aux.clear();

    for (auto to : list[node])
        if (deny != to)
            aux.pb(dp[to]);

    ans = aux.size() + 1;
    sort(aux.begin(), aux.end());
    reverse(aux.begin(), aux.end());

    for (auto e : aux)
        ans = (ans * base + e) % mod;

    ans = (ans * base + aux.size() * 1311) % mod;

    return ans;
}

void dfs(int node, int root) {

    for (auto to : list[node])
        if (to != root)
            dfs(to, node);

    dp[node] = compute(node, root);
}

void solve(int node, int root) {
    if (list[node].size() < 4)
        sol.pb(compute(node, 0));

    for (auto to : list[node]) {
        if (to == root) continue;
        dp[node] = compute(node, to);
        solve(to, node);
    }

    dp[node] = compute(node, root);
}

int main()
{
    //freopen("test.in","r",stdin);

    scanf("%d", &n);
    for (i = 1; i < n; i++) {
        scanf("%d%d", &x, &y);
        list[x].pb(y);
        list[y].pb(x);
    }

    dfs(1, 0);
    solve(1, 0);

    sort(sol.begin(), sol.end());
    sol.resize(unique(sol.begin(), sol.end()) - sol.begin());

    printf("%d\n", sol.size());

    return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define Q 19260817
#define mod 993729403
#define mod2 806053187
#define Q2 79845453
#define maxn 100001
int head[maxn],nxt[maxn<<2],ver[maxn<<2],tot;int n;int d[maxn];
map<pair<int,int>,int> hash,hash2;
map<int,bool> mp,mp2;
inline int cube(int x){return x*x%mod*x%mod;}
inline int cube2(int x){return x*x%mod2*x%mod2;}
inline void addedge(int a,int b)
{
	nxt[++tot]=head[a];ver[tot]=b;head[a]=tot;d[a]++;
	nxt[++tot]=head[b];ver[tot]=a;head[b]=tot;d[b]++;
}
inline int calc_hash(int x,int fa)
{
	if(hash[make_pair(x,fa)]) return hash[make_pair(x,fa)];
	int res=Q;
	for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa) res=(res+cube(calc_hash(ver[i],x)))%mod;
	hash[make_pair(x,fa)]=res;
	return res;
}
inline int calc_hash2(int x,int fa)
{
	if(hash2[make_pair(x,fa)]) return hash2[make_pair(x,fa)];
	int res=Q2;
	for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa) res=(res+cube2(calc_hash2(ver[i],x)))%mod2;
	hash2[make_pair(x,fa)]=res;
	return res;
}
inline bool calc(int x)
{
	hash[make_pair(0,0)]=hash2[make_pair(0,0)]=0;
	head[0]=0;nxt[++tot]=head[0];ver[tot]=x;head[0]=tot;d[x]++;
	int hhh=calc_hash(0,0),hhh2=calc_hash2(0,0);
	if(mp[hhh]&&mp2[hhh2]) return tot--,d[x]--,0;
	mp[hhh]=mp2[hhh2]=1;
	return tot--,d[x]--,1;
}
inline void init()
{
	scanf("%I64d",&n);
	for(int i=1,a,b;i<n;i++) scanf("%I64d%I64d",&a,&b),addedge(a,b);
}
signed main()
{
	init();
	int res=0;
	for(int i=1;i<=n;i++) if(d[i]<4&&calc(i)) res++;
	cout<<res;
}

#include <bits/stdc++.h>
#define LL long long
#define pii pair <LL, LL>
#define xx first
#define yy second
using namespace std;

const int N = 100100;
const LL A1 = 23, B1 = 17, C1 = 233, D1 = 19, mod1 = 1e9 + 7;
const LL A2 = 233, B2 = 19, C2 = 29, D2 = 23, mod2 = 1e9 + 9;

map <pii, pii> mp;
vector <int> g[N];
int u[N], v[N];

pii dfs (int u, int fa) {
    if (mp.find (pii (u, fa)) != mp.end()) return mp[pii (u, fa)];
    vector <pii> tmp;
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if (v == fa) continue;
        tmp.push_back (dfs (v, u));
    }
    sort (tmp.begin(), tmp.end());
    LL h1 = g[u].size(), h2 = g[u].size();
    for (int i = 0; i < tmp.size(); i++) {
        h1 = (((h1 * A1 + B1) ^ tmp[i].xx) + C1) % mod1;
        h2 = (((h2 * A2 + B2) ^ tmp[i].yy) + C2) % mod2;
    }
    (h1 += D1) %= mod1;
    (h2 += D2) %= mod2;
//    cout << u << ' ' << fa << ' ' << h1 << ' ' << h2 << endl;
    return mp[pii (u, fa)] = pii (h1, h2);
}

int main () {
//    freopen ("in", "r", stdin);
    int n;
    cin >> n;
    for (int i = 1; i < n; i++) {
        scanf ("%d%d", &u[i], &v[i]);
        g[u[i]].push_back (v[i]);
        g[v[i]].push_back (u[i]);
    }
    set <pii> st;
    for (int i = 1; i <= n; i++) {
        if (g[u[i]].size() < 4) st.insert (dfs (i, 0));
//        cout << dfs (i, 0).xx << ' ' << dfs (i, 0).yy << endl;
//        if (g[v[i]].size() < 4) st.insert (dfs (v[i], u[i]));
    }
    cout << st.size() << endl;
}

#include<map>
#include<cstdio>
#include<iostream>
using namespace std;
typedef unsigned long long LL;
typedef unsigned int INT;
typedef pair<LL, INT> Hash;
#define gc c=getchar()
int read() {
	int x = 0, f = 1; char gc;
	for (; !isdigit(c); gc)if (c == '-')f = -1;
	for (; isdigit(c); gc)x = x * 10 + c - '0';
	return x * f;
}
#undef gc
const int MAXN = 100005;
map<int, pair<LL, INT> >f[MAXN];
map<pair<LL, INT>, bool>vis;
int deg[MAXN];
int nedge, head[MAXN];
struct Edge {
	int to, nxt;
} edge[MAXN * 2];
void add(int x, int y) {
	edge[++nedge].to = y;
	edge[nedge].nxt = head[x];
	head[x] = nedge;
}
Hash dfs(int k, int fa) {
	if (f[k][fa].first || f[k][fa].second)return f[k][fa];
	Hash res;
	res.first = 10000000007;
	res.second = 10000000007;
	for (int i = head[k]; i; i = edge[i].nxt) {
		int u = edge[i].to;
		if (u == fa)continue;
		Hash tmp = dfs(u, k);
		res.first += tmp.first * tmp.first * tmp.first;
		res.second += tmp.second * tmp.second * tmp.second;
	}
	return f[k][fa] = res;
}
int main() {
	int n = read();
	for (int i = 1; i < n; i++) {
		int x = read(), y = read();
		add(x, y); add(y, x);
		deg[x]++; deg[y]++;
	}
	int ans = 0;
	for (int i = 1; i <= n; i++)
		if (deg[i] < 4) {
			Hash tmp = dfs(i, 0);
			if (!vis[tmp])ans++, vis[tmp] = 1;
		}
	printf("%d", ans);
}

//看看会不会爆int!
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
#define FOR(i, l, r) for(int i = l; i <= r; i++)
#define ROF(i, r, l) for(int i = r; i >= l; i--)
#define all(a) a.begin(), a.end()
inline int ckmax(int &a, int b) { return a < b ? a = b, 1 : 0; }
inline int ckmin(int &a, int b) { return a > b ? a = b, 1 : 0; }
#define clean(a) memset(a, 0, sizeof(a))
typedef long long ll;

const int M1 = 1e9 + 7;
const int M2 = 1e9 + 8;
const int P = 239;
const int PP = 17;
const int maxn = 100100;

struct Hash{
	int num1, num2;
	Hash(int num1 = 0, int num2 = 0): num1(num1), num2(num2) {}
	bool operator < (const Hash &a) const{
		return mkp(num1, num2) < mkp(a.num1, a.num2);
	}
	Hash operator * (const int &P) const{
		return Hash((ll)num1 * P % M1, (ll)num2 * P % M2);
	}
	Hash operator + (const Hash &a) const{
		return Hash((num1 + a.num1) % M1, (num2 + a.num2) % M2);
	}
};
map<Hash, int> mp;
map<pair<int, int>, Hash> H;
int n, u, v, du[maxn];
vector<int> g[maxn];

Hash dfs(int x, int fa){
	if(H.count(mkp(x, fa))) return H[mkp(x, fa)];
	vector<Hash> vec;
	for(auto v : g[x])
		if(v != fa)
			vec.pb(dfs(v, x));
	sort(all(vec));
	Hash has;
	for(auto v : vec)
		has = has * P + v;
	has = has * PP + Hash(2, 2);
	return H[mkp(x, fa)] = has;
}

int main(){
#ifndef ONLINE_JUDGE
	freopen("x.in", "r", stdin);
	freopen("x.out", "w", stdout);
#endif
	scanf("%d", &n);
	for(int i = 1; i < n; ++i){
		scanf("%d%d", &u, &v);
		du[u]++, du[v]++;
		g[u].pb(v);
		g[v].pb(u);
	}

	for(int i = 1; i <= n; ++i)
		if(du[i] <= 3) mp[dfs(i, 0)]++;

	printf("%d\n", mp.size());
  return 0;
}
/*
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         佛祖保佑       永无BUG
*/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
const int mod1=34243259;
const int jia1=323422;
const int mod2=34354349;
const int jia2=123321;
int n,du[100005][5];
int tot,head[100005],nx[200005],to[200005];
struct node
{
	int x,y;
	bool operator < (const node &aa)const
	{
		return x==aa.x?y<aa.y:x<aa.x;
	}
}f[100005][5];
map<node,int>mp;
void jia(int aa,int bb)
{
	tot++;
	nx[tot]=head[aa];
	to[tot]=bb;
	head[aa]=tot;
	return;
}
node dfs(int rt,int fa)
{
	int ans=0;
	for(int i=1;i<=du[rt][0];i++) if(fa==du[rt][i]) ans=i;
	if(f[rt][ans].x) return f[rt][ans];
	node kk;
	kk.x=jia1;
	kk.y=jia2;
	for(int i=head[rt];i;i=nx[i])
	{
		int yy=to[i];
		if(yy==fa) continue;
		node rr=dfs(yy,rt);
		kk.x=(kk.x+rr.x*rr.x%mod1*rr.x%mod1)%mod1;
		kk.y=(kk.y+rr.y*rr.y%mod2*rr.y%mod2)%mod2;
	}
	return f[rt][ans]=kk;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;++i)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		jia(x,y);
		jia(y,x);
		du[x][0]++;
		du[x][du[x][0]]=y;
		du[y][0]++;
		du[y][du[y][0]]=x;
	}
	int sum=0;
	for(int i=1;i<=n;++i)
	if(du[i][0]<4)
	{
		node tt=dfs(i,0);
		if(!mp[tt])
		{
			mp[tt]=1;
			sum++;
		}
	}
	cout<<sum;
	return 0;
}