#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*109457+x*201712589+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^=du[x]*du[x];
	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 <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 <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<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 <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;
}

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

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

/* 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 <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<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<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<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>
#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 <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<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 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>
#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<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>

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

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

//尽人事，听天命。明天会更好。--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 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<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 <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]);
	}
}

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

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

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

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

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

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

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