// Slower C++ solution:
//

/*

ID: kfoozmi1

LANG: C++

TASK:

*/

#include <bits/stdc++.h>

using namespace std;



#ifdef kfoozminus

#define dbg(args...) do {cerr << #args << " : "; faltu(args); } while(0)



void faltu() {

	cerr << endl;

}



template <typename T>

void faltu(T a[], int n) {

	for(int i = 0; i < n; ++i) cerr << a[i] << ' ';

	cerr << endl;

}



template <typename First, typename ... hello>

void faltu(First arg, const hello&... rest) {

	cerr << arg << ' ';

	faltu(rest...);

}

#else

#define dbg(args...)

#endif



#define PB push_back

#define F first

#define S second

#define MP make_pair

#define SQR(a) ((a) * (a))

#define vsort(v) sort(v.begin(), v.end())

#define memset(a, b) memset(a, b, sizeof a)

#define PQ priority_queue

#define PI acos(-1)

#define EPS 1e-9



#define B1 43

#define B2 43



#define MOD1 1000000007

#define MOD2 1000000009



typedef long long ll;

typedef pair<int, int> pii;

typedef pair<ll, ll> pll;



//int dx[] = {0, 0, +1, -1};

//int dy[] = {+1, -1, 0, 0};

//int dx[] = {+1, 0, -1, 0, +1, +1, -1, -1};

//int dy[] = {0, +1, 0, -1, +1, -1, +1, -1};



inline bool checkBit(ll n, int i) { return n & (1LL << i); }

inline ll setBit(ll n, int i) { return n | (1LL << i); }

inline ll resetBit(ll n, int i) { return n & (~ (1LL << i)); }

inline bool EQ(double a, double b) { return fabs(a-b) < EPS; }

inline double dist(double ix, double iy, double jx, double jy) { return sqrt(SQR(ix - jx) + SQR(iy - jy)); }



#define PMX 1000000



int marked[PMX/64+2];



#define mark(x) marked[x>>6] |= (1<<((x&63)>>1))

#define check(x) (marked[x>>6] & (1<<((x&63)>>1)))



bool isPrime(int x)

{

    return (x>1) && ((x==2) || ((x&1) && (!(check(x)))));

}



void seive(int n)

{

    int i, j;

    for(i=3; i*i<=n; i+=2)

    {

        if(!check(i))

        {

            for(j=i*i; j<=n; j+=i<<1)

            {

                mark(j);

            }

        }

    }

}



ll bigMod(ll a, ll b, ll MOD)

{

	ll r = 1;

	while(b) {

		if(b & 1) (r *= a) %= MOD;

		b >>= 1;

		(a *= a) %= MOD;

	}

	return r;

}



ll add(ll a, ll b, ll MOD)

{

	ll ret = a + b;

	if(ret >= MOD) ret -= MOD;

	return ret;

}



ll sub(ll a, ll b, ll MOD)

{

	ll ret = a - b;

	if(ret < 0) ret += MOD;

	return ret;

}



ll mul(ll a, ll b, ll MOD)

{

	ll ret = a * b;

	if(ret >= MOD) ret %= MOD;

	return ret;

}



#define INF 100000000

#define MX 100007



map< pll, ll > mp;

ll ans;

vector<int> edge[MX];



pll dfs(int nd)

{

	dbg(nd);

	pll h = {0, 0};

	for(int k = 0; k < edge[nd].size(); k ++) {



		pll p = dfs(edge[nd][k]);

		h.F = add(h.F, p.F, MOD1);

		h.S = add(h.S, p.S, MOD2);

	}

	h.F = add(mul(h.F, B1, MOD1), 1, MOD1);

	h.S = add(mul(h.S, B2, MOD2), 1, MOD1);

	ans += mp[h];

	mp[h] ++;

	return h;

}



int main()

{

#ifdef kfoozminus

	//freopen("in", "r", stdin);

	//freopen("out", "w", stdout);

#endif

	int n, i, u, v;



	scanf("%d", &n);

	for(i = 1; i < n; i ++) {



		scanf("%d %d", &u, &v);

		edge[u].PB(v);

	}

	dfs(1);

	printf("%lld\n", ans);

        return 0;

}

// Faster C++ solution for the same problem (measured speedup: 3.5158138557186507x):
#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <map>



#define MAXN 100005



using namespace std;



struct edge

{

	int y,next;

};



edge v[2*MAXN];

int head[MAXN];

int tot = 0;

long long ans = 0;

map<unsigned long long,int> S;



void add(int x,int y)

{

	tot++;

	v[tot].y = y;

	v[tot].next = head[x];

	head[x] = tot;

}



unsigned long long dfs(int x,int fa)

{

	unsigned long long temp = 1;

	for (int i=head[x];i;i=v[i].next)

	{

		if (v[i].y == fa) continue;

		temp += 131*dfs(v[i].y,x);

	}

	ans += S[temp];

	S[temp]++;

	return temp;

}



int main()

{

	int x,y,n;

	scanf("%d",&n);

	for (int i=1;i<n;i++)

	{

		scanf("%d%d",&x,&y);

		add(x,y);

		add(y,x);

	}



	S.clear();

	ans = 0;

	dfs(1,0);



	cout << ans << endl;

	return 0;

}