//satyaki3794
#include <bits/stdc++.h>
#define gc getchar_unlocked
#define pc putchar_unlocked
#define PI (3.14159265)
#define ff first
#define ss second
#define pb push_back
#define MOD (1000000007LL)
#define INF (100000005)
#define SIZE (2)
#define TREESIZE (302144)
#define LEFT(n) (2*n)
#define RIGHT(n) (2*n+1)
#define epsilon 1e8 //add to double before casting to integer
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> ii;
typedef pair<ii, int> iii;
#define N 100005
int n;
vector<int> adj[N];
ll ans = 0;
ll distDown[N][3], distUp[N], subtreeDia[N];
void dfs1(int, int);
void dfs2(int, int);
void dfs3(int, int);
int main()
{
ios_base::sync_with_stdio(0);
// freopen("input.txt", "r", stdin);
cin>>n;
int e = n-1;
while(e--){
int a, b;
cin>>a>>b;
adj[a].pb(b);
adj[b].pb(a);
}
//calculate 1st, 2nd and 3rd max distances from each vertex in its subtree
//and diameter if subtree of v
dfs1(1, -1);
//calculate max dist from each vertex to vertices towards its parent, i.e. not in its subtree
dfs2(1, -1);
ans = 0;
//now for each vertex v, we assume it is a part of one of the diameters
//and that the other diameter lies in one of its subtrees
//find max of such products for all vertices
dfs3(1, -1);
cout<<ans;
return 0;
}
void dfs1(int v, int par){
distDown[v][0] = distDown[v][1] = distDown[v][2] = 0;
subtreeDia[v] = 0;
for(int i=0;i<(int)adj[v].size();i++){
int vv = adj[v][i];
if(vv == par) continue;
dfs1(vv, v);
subtreeDia[v] =max(subtreeDia[v], subtreeDia[vv]);
if(distDown[vv][0]+1 >= distDown[v][0]){
distDown[v][2] = distDown[v][1];
distDown[v][1] = distDown[v][0];
distDown[v][0] = distDown[vv][0]+1;
}
else if(distDown[vv][0]+1 >= distDown[v][1]){
distDown[v][2] = distDown[v][1];
distDown[v][1] = distDown[vv][0]+1;
}
else if(distDown[vv][0]+1 >= distDown[v][2]){
distDown[v][2] = distDown[vv][0]+1;
}
}
subtreeDia[v] = max(subtreeDia[v], distDown[v][0]+distDown[v][1]);
}
void dfs2(int v, int par){
distUp[v] = 0;
if(par != -1){
distUp[v] = max(distUp[v], 1 + distUp[par]);
if(distDown[v][0]+1 == distDown[par][0]) distUp[v] = max(distUp[v], 1+distDown[par][1]);
else distUp[v] = max(distUp[v], 1+distDown[par][0]);
}
for(int i=0;i<(int)adj[v].size();i++){
int vv = adj[v][i];
if(vv == par) continue;
dfs2(vv, v);
}
}
void dfs3(int v, int par){
//we iterate through all children and assume other diameter in in the subtree of that child
for(int i=0;i<(int)adj[v].size();i++){
int vv = adj[v][i];
if(vv == par) continue;
ll sd = subtreeDia[vv];
//now for the diameter involving v itself
//it has 2 ends and v is in the middle
//both ends can either be in subtree of v itself
//or one can be in subtree and other up towards its parent
if(distDown[vv][0]+1 == distDown[v][0]){
ll temp = sd * (distDown[v][1] + distDown[v][2]);
ans = max(ans, temp);
temp = sd * (distDown[v][1] + distUp[v]);
ans = max(ans, temp);
}
else if(distDown[vv][0]+1 == distDown[v][1]){
ll temp = sd * (distDown[v][0] + distDown[v][2]);
ans = max(ans, temp);
temp = sd * (distDown[v][0] + distUp[v]);
ans = max(ans, temp);
}
else{
ll temp = sd * (distDown[v][0] + distDown[v][1]);
ans = max(ans, temp);
temp = sd * (distDown[v][0] + distUp[v]);
ans = max(ans, temp);
}
dfs3(vv, v);
}
}