Problem:
Problem K: Encampment Game
Problem
$N$頂点の木がある。各頂点はそれぞれ1から$N$の番号が割り振られている。
Gacho君と川林君はこの木を使って陣取りゲームをすることにした。
ゲームはGacho君と川林君が異なる頂点にいる状態からスタートする。
Gacho君から交互に頂点を移動することを繰り返し、最初に移動できなくなった方が負けである。
移動方法:
頂点$x$にいる時、頂点$x$と辺で直接結ばれているまだ誰も訪れたことがない頂点のいずれかに移動する。
そのような頂点が存在しない場合、移動することはできない。
Gacho君が最初にいる頂点を頂点$A$、川林君が最初にいる頂点を頂点$B$とする。
Gacho君と川林君が互いに最善を尽くしたとき、Gacho君が勝つことになる頂点$A$と頂点$B$の組み合わせの通り数を求めよ。
Input
入力は以下の形式で与えられる。
$N$
$u_1$ $v_1$
$u_2$ $v_2$
$\vdots$
$u_{N-1}$ $v_{N-1}$
入力はすべて整数で与えられる。
1行目に頂点数$N$が与えられる。
2行目から続く$N-1$行に木の辺の情報が空白区切りで与えられる。
$1+i$行目の入力は頂点$u_i$と頂点$v_i$が辺で結ばれていることを表す。
Constraints
入力は以下の条件を満たす。
$2 \leq N\leq 2000 $
$ 1 \leq u_i, v_i \leq N$
与えられるグラフは木である
Output
Gacho君が勝つ頂点$A$と頂点$B$の組み合わせの通り数を1行に出力せよ。
Sample Input 1
2
1 2
Sample Output 1
0
頂点$A$と頂点$B$の組み合わせは(1, 2), (2, 1)の2通りあり、どちらもGacho君は初手で移動することができないので必ず負ける。
Sample Input 2
6
1 2
2 3
3 4
4 5
5 6
Sample Output 2
12
Sample Input 3
5
1 2
1 3
3 4
3 5
Sample Output 3
12
Sample Input 4
20
14 1
2 1
18 14
10 1
12 10
5 1
17 5
7 1
11 17
4 1
19 2
15 1
3 19
8 15
9 8
20 8
6 1
16 15
13 7
Sample Output 4
243

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll=long long;
const ll ILL=2167167167167167167;
const int INF=2100000000;
#define rep(i,a,b) for (int i=(int)(a);i<(int)(b);i++)
#define all(p) p.begin(),p.end()
template<class T> using _pq = priority_queue<T, vector<T>, greater<T>>;
template<class T> int LB(vector<T> &v,T a){return lower_bound(v.begin(),v.end(),a)-v.begin();}
template<class T> int UB(vector<T> &v,T a){return upper_bound(v.begin(),v.end(),a)-v.begin();}
template<class T> bool chmin(T &a,T b){if(b<a){a=b;return 1;}else return 0;}
template<class T> bool chmax(T &a,T b){if(a<b){a=b;return 1;}else return 0;}
template<class T> void So(vector<T> &v) {sort(v.begin(),v.end());}
template<class T> void Sore(vector<T> &v) {sort(v.begin(),v.end(),[](T x,T y){return x>y;});}
bool yneos(bool a,bool upp=false){if(a){cout<<(upp?"YES\n":"Yes\n");}else{cout<<(upp?"NO\n":"No\n");}return a;}
template<class T> void vec_out(vector<T> &p,int ty=0){
    if(ty==2){cout<<'{';for(int i=0;i<(int)p.size();i++){if(i){cout<<",";}cout<<'"'<<p[i]<<'"';}cout<<"}\n";}
    else{if(ty==1){cout<<p.size()<<"\n";}for(int i=0;i<(int)(p.size());i++){if(i) cout<<" ";cout<<p[i];}cout<<"\n";}}
template<class T> T vec_min(vector<T> &a){assert(!a.empty());T ans=a[0];for(auto &x:a) chmin(ans,x);return ans;}
template<class T> T vec_max(vector<T> &a){assert(!a.empty());T ans=a[0];for(auto &x:a) chmax(ans,x);return ans;}
template<class T> T vec_sum(vector<T> &a){T ans=T(0);for(auto &x:a) ans+=x;return ans;}
int pop_count(long long a){int res=0;while(a){res+=(a&1),a>>=1;}return res;}
template<class T> T square(T a){return a * a;}



void solve();
// POP'N ROLL MUSIC / TOMOO
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t = 1;
    // cin >> t;
    rep(i, 0, t) solve();
}

void solve(){
    int N;
    cin >> N;
    vector<vector<int>> G(N);
    rep(i, 0, N - 1){
        int a, b;
        cin >> a >> b;
        a--, b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    vector dp(N + 1, vector<int>(N + 1));
    vector top3(N, vector<int>(3));
    vector dist(N, vector<int>(N + 1));
    vector pare(N, vector<int>(N));
    vector pre(N, vector<int>(N, -INF));
    // dist table を埋める
    {
        rep(i, 0, N){
            auto dfs = [&](auto self, int v, int p) -> int {
                pare[i][v] = p;
                int tmp = 0;
                for (auto x : G[v]) if (x != p){
                    chmax(tmp, self(self, x, v));
                }
                return tmp + 1;
            };
            for (auto x : G[i]){
                dist[i][x] = dfs(dfs, x, i);
                if (chmax(top3[i][2], dist[i][x])){
                    for (int j = 1; j >= 0; j--){
                        if (top3[i][j] < top3[i][j + 1]){
                            swap(top3[i][j], top3[i][j + 1]);
                        }
                    }
                }
            }
        }
    }
    auto f = [&](int var, int a, int b) -> int {
        a = dist[var][a];
        b = dist[var][b];
        if (a < b) swap(a, b);
        if (top3[var][0] != a) return top3[var][0];
        if (top3[var][1] != b) return top3[var][1];
        return top3[var][2];
    };
    {
        rep(i, 0, N) {
            auto dfs = [&](auto self, int v, int p) -> void {
                for (auto y : G[v]) if (y != p){
                    chmax(pre[i][y], pre[i][v] + 1);
                    chmax(pre[i][y], f(v, y, p));
                    self(self, y, v);
                }
            };
            for (auto x : G[i]) dfs(dfs, x, i);
        }
    }
    auto solve = [&](auto self, int a, int na, int b, int nb) -> int {
        if (na < N && dp[na][nb] != 0){
            return dp[na][nb];
        }
        // 近づいかなかったときに勝てるか？
        int A = f(a, na, pare[b][a]);
        int B = pre[a][b];
        B++;
        chmax(B, f(b, pare[a][b], nb));
        if (A > B){
            dp[na][nb] = 1;
        }

        // めちゃ近い
        else if (pare[a][b] == a){
            dp[na][nb] = -1;
            if (f(a, na, b) > f(b, nb, a)) dp[na][nb] = 1;
        }

        // 再帰させる
        else{
            dp[na][nb] = self(self, b, nb, pare[b][a], a) * -1;
        }
        // cout << a << " " << na << " " << b << " " << nb << " " << dp[na][nb] << endl;
        return dp[na][nb];
    };
    int ans = 0;
    rep(i, 0, N) rep(j, 0, N) if (i != j){
        ans += max(0, solve(solve, i, N, j, N));
    }
    cout << ans << "\n";
}
/*
 * 解説読んだけどよくわからないので、top3 を持つ
 */
accuracy: 1
time_ms: 490
memory_kb: 66264
final_rank: 2

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}

struct FastIO{
  FastIO(){
    cin.tie(0);
    ios::sync_with_stdio(0);
  }
}fastio_beet;

template <typename T, typename F>
struct SegmentTree{
  // using F = function<T(T,T)>;
  int n;
  F f;
  T ti;
  vector<T> dat;
  SegmentTree(){};
  SegmentTree(F f,T ti):f(f),ti(ti){}
  void init(int n_){    
    n=1;
    while(n<n_) n<<=1;
    dat.assign(n<<1,ti);
  }
  void build(const vector<T> &v){
    int n_=v.size();
    init(n_);
    for(int i=0;i<n_;i++) dat[n+i]=v[i];
    for(int i=n-1;i;i--)
      dat[i]=f(dat[(i<<1)|0],dat[(i<<1)|1]);
  }
  void set_val(int k,T x){
    dat[k+=n]=x;
    while(k>>=1)
      dat[k]=f(dat[(k<<1)|0],dat[(k<<1)|1]);    
  }
  T query(int a,int b){
    T vl=ti,vr=ti;
    for(int l=a+n,r=b+n;l<r;l>>=1,r>>=1) {
      if(l&1) vl=f(vl,dat[l++]);
      if(r&1) vr=f(dat[--r],vr);
    }
    return f(vl,vr);
  }
};

//INSERT ABOVE HERE
const int MAX = 5050;
int dp[2][MAX][MAX];
signed main(){
  int n;
  cin>>n;
  vector<vector<int> > G(n);
  for(int i=1;i<n;i++){
    int x,y;
    cin>>x>>y;
    x--;y--;
    G[x].emplace_back(y);
    G[y].emplace_back(x);
  }
  if(n==2){
    cout<<0<<endl;
    return 0;
  }
  for(int i=0;i<MAX;i++)
    for(int j=0;j<MAX;j++)
      dp[0][i][j]=dp[1][i][j]=MAX;

  vector<int> hs(n),dep(n);
  using P = pair<int, int>;  
  vector<vector<P> > vp(n);
  
  vector<vector<vector<int> > > H(2,vector<vector<int> >(n));
  vector<vector< deque<int> > > ds(2,vector<deque<int> >(n));
  
  function<void(int, int, int)> dfs1=
    [&](int v,int p,int d)->void{      
      hs[v]=0;
      dep[v]=d;
      
      vp[v].clear();
      ds[0][v].clear();
      ds[1][v].clear();
      H[0][v].clear();
      H[1][v].clear();
      
      for(int u:G[v]){
        if(u==p) continue;
        dfs1(u,v,d+1);
        chmax(hs[v],hs[u]+1);      
        vp[v].emplace_back(hs[u]+1,u);  
      }
      sort(vp[v].rbegin(),vp[v].rend());
    };
  
  auto f=[&](int a,int b){return max(a,b);};
  SegmentTree<int, decltype(f)> seg(f,-1);
  seg.build(vector<int>(n,-1));
  
  vector<queue<int> > ss(2);
  function<void(int, int, int)> dfs2=
    [&](int r,int v,int p){
      ds[0][v].emplace_front(v);
      ds[1][v].emplace_front(v);
      if(vp[v].size()==0u) return;
      
      if(vp[v].size()==1u)
        vp[v].emplace_back(0,-1);
      
      int l=vp[v][0].second;
      for(int u:G[v]){
        if(u==p) continue;
        seg.set_val(dep[v],dep[v]+vp[v][u==l].first);        
        dfs2(r,u,v);        
      }
      
      for(int k=0;k<2;k++){
        auto unite=
          [&](int x,int y)->void{          
            if(ds[k][x].size()<ds[k][y].size()) swap(ds[k][x],ds[k][y]);
            for(int i=0;i<(int)ds[k][y].size();i++){
              if(ds[k][x][i]<ds[k][y][i])
                swap(ds[k][x][i],ds[k][y][i]);
              if(~ds[k][y][i])
                H[k][ds[k][x][i]].emplace_back(ds[k][y][i]);
            }
          };
        
        for(int u:G[v]){
          if(u==p) continue;
          ds[k][u].emplace_front(-1);
          if(u!=l) unite(v,u);
        }
        
        auto inch=
          [&](int x,int sd)->void{
            while(!ds[k][x].empty()){
              int y=ds[k][x].back();
              if(y<0){
                ds[k][x].pop_back();
                continue;
              }
              if(y==r) break;
              int dist=dep[y]-dep[v];
              
              // dist+(dist+k) -1 +1
              if(dist+(dist+k)==dep[y]){
                if(dist+sd+k>seg.query(dist+k-1,dep[v])){
                  dp[k][r][y]=v;
                  ss[k].emplace(y);
                  ds[k][x].pop_back();
                  continue;
                }
              }
              
              if(dist+(dist+k)>=dep[y]){
                ds[k][x].pop_back();
                continue;              
              }
              
              if(dist+sd+k>seg.query(dist+k,dep[v])){
                dp[k][r][y]=v;
                ss[k].emplace(y);
                ds[k][x].pop_back();
                continue;
              }
              return;   
            }
          };
        
        inch(v,vp[v][0].first);
        inch(l,vp[v][1].first);
        
        unite(v,l);
      }
    };
  

  for(int i=0;i<n;i++){
    dfs1(i,-1,0);
    dfs2(i,i,-1);

    for(int k=0;k<2;k++){
      while(!ss[k].empty()){
        int v=ss[k].front();ss[k].pop();
        for(int u:H[k][v]){
          dp[k][i][u]=dp[k][i][v];
          ss[k].emplace(u);
        }
      }
      
      for(int j=0;j<n;j++)
        if(dp[k][i][j]!=MAX)
          dp[k][i][j]=dep[j]-dep[dp[k][i][j]];
    }    
  }
  
  int ans=0;
  for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
      if(i!=j) ans+=dp[0][i][j]<=dp[1][j][i];
  
  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 1260
memory_kb: 207448
final_rank: 3

code_snippet: #include <bits/stdc++.h>

using namespace std;

int N;
vector< int > g[2000];
vector< int > ord;
int ans;
int dep[2000], upd[2000];

int dfs(int idx, int par) {
  dep[idx] = 0;
  for(auto to : g[idx]) {
    if(to == par) continue;
    dfs(to, idx);
    dep[idx] = max(dep[idx], dep[to] + 1);
  }
}

const int INF = 1 << 30;


map< pair< int, int >, int > dp2[2002][2002];

int rec3(int p, int q, int par1 = -1, int par2 = -1) {
  if(p >= q) return -INF;
  if(dp2[ord[p]][ord[q]].count({par1, par2})) return dp2[ord[p]][ord[q]][{par1, par2}];
  return dp2[ord[p]][ord[q]][{par1, par2}] = max(upd[ord[q]], rec3(p, q - 1, ord[q], ord[1]) + 1);
}

map< pair< int, int >, int > dp4[2002][2002];


int rec4(int p, int q, int par1 = -1, int par2 = -1) {
  if(p >= q) return -INF;
  if(dp4[ord[p]][ord[q]].count({par1, par2})) return dp4[ord[p]][ord[q]][{par1, par2}];
  return dp4[ord[p]][ord[q]][{par1, par2}] = max(upd[ord[p]], rec4(p + 1, q, ord[p], ord[ord.size() - 2]) + 1);
}


bool memo[2002][2002][2];
int dp[2002][2002][2];

int rec2(int p, int q, bool tern, int f = 0) {
  if(p >= q) return true;
  //if(memo[ord[p]][ord[q]][tern]) return dp[ord[p]][ord[q]][tern];

  bool ret = false;
  if(tern) {
    if(!rec2(p, q - 1, tern ^ 1, f + 1)) ret = true;
    if(upd[ord[q]] > rec4(p, q, -1, ord[ord.size() - 2])) ret = true;
  } else {
    if(!rec2(p + 1, q, tern ^ 1, f + 1)) ret = true;
    if(upd[ord[p]] > rec3(p, q, -1, ord[1])) ret = true;
  }
  memo[ord[p]][ord[q]][tern] = true;
  return dp[ord[p]][ord[q]][tern] = ret;
}


int rec(int idx, int par) {
  ord.emplace_back(idx);
  pair< int, int > a(0, -1), b(0, -1);
  for(auto to : g[idx]) {
    if(to == par) continue;
    if(make_pair(dep[to] + 1, to) > a) {
      b = a;
      a = make_pair(dep[to] + 1, to);
    } else if(make_pair(dep[to] + 1, to) > b) {
      b = make_pair(dep[to] + 1, to);
    }
  }
  for(auto to : g[idx]) {
    if(to == par) continue;
    upd[idx] = a.second == to ? b.first : a.first;
    rec(to, idx);
  }
  upd[idx] = a.first;
  if(ord.size() >= 2 && rec2(0, ord.size() - 1, false)) {
    ++ans;
  }
  ord.pop_back();
}


int main() {
  cin >> N;
  for(int i = 1; i < N; i++) {
    int a, b;
    cin >> a >> b;
    --a, --b;
    g[a].emplace_back(b);
    g[b].emplace_back(a);
  }
  for(int i = 0; i < N; i++) {
    dfs(i, -1);
    rec(i, -1);
  }
  cout << ans << endl;
}
accuracy: 0.13333333333333333
time_ms: 110
memory_kb: 379376
final_rank: 14

code_snippet: #include <bits/stdc++.h>

using namespace std;

int N;
vector< int > g[2000];
vector< int > ord;
int ans;
int dep[2000], upd[2000];

int dfs(int idx, int par) {
  dep[idx] = 0;
  for(auto to : g[idx]) {
    if(to == par) continue;
    dfs(to, idx);
    dep[idx] = max(dep[idx], dep[to] + 1);
  }
}

const int INF = 1 << 30;

bool memo2[2002][2002];
int dp2[2002][2002];

int rec3(int p, int q, int f = 0) {
  if(p >= q) return -INF;
  if(f >= 9 && memo2[ord[p]][ord[q]]) return dp2[ord[p]][ord[q]];
  if(f >= 9) {
    memo2[ord[p]][ord[q]] = true;
    return dp2[ord[p]][ord[q]] = max(upd[ord[q]], rec3(p, q - 1, true) + 1);
  }
  return max(upd[ord[q]], rec3(p, q - 1, f + 1) + 1);
}


bool memo3[2002][2002];
int dp3[2002][2002];

int rec4(int p, int q, int f = false) {
  if(p >= q) return -INF;
  if(f >= 8 && memo3[ord[p]][ord[q]]) return dp3[ord[p]][ord[q]];
  if(f >= 8) {
    memo3[ord[p]][ord[q]] = true;
    return dp3[ord[p]][ord[q]] = max(upd[ord[p]], rec4(p + 1, q, true) + 1);
  }
  return max(upd[ord[p]], rec4(p + 1, q, f + 1) + 1);
}


bool memo[2002][2002][2];
int dp[2002][2002][2];

int rec2(int p, int q, bool tern, int f = 0) {
  if(p >= q) return true;
  if(f >= 25 && memo[ord[p]][ord[q]][tern]) return dp[ord[p]][ord[q]][tern];

  bool ret = false;
  if(tern) {
    if(!rec2(p, q - 1, tern ^ 1, f + 1)) ret = true;
    if(upd[ord[q]] > rec4(p, q)) ret = true;
  } else {
    if(!rec2(p + 1, q, tern ^ 1, f + 1)) ret = true;
    if(upd[ord[p]] > rec3(p, q)) ret = true;
  }
  if(f >= 25) {
    memo[ord[p]][ord[q]][tern] = true;
    return dp[ord[p]][ord[q]][tern] = ret;
  }
  return ret;
}


int rec(int idx, int par) {
  ord.emplace_back(idx);
  pair< int, int > a(0, -1), b(0, -1);
  for(auto to : g[idx]) {
    if(to == par) continue;
    if(make_pair(dep[to] + 1, to) > a) {
      b = a;
      a = make_pair(dep[to] + 1, to);
    } else if(make_pair(dep[to] + 1, to) > b) {
      b = make_pair(dep[to] + 1, to);
    }
  }
  for(auto to : g[idx]) {
    if(to == par) continue;
    upd[idx] = a.second == to ? b.first : a.first;
    rec(to, idx);
  }
  upd[idx] = a.first;
  if(ord.size() >= 2 && rec2(0, ord.size() - 1, false)) {
    ++ans;
  }
  ord.pop_back();
}


int main() {
  cin >> N;
  for(int i = 1; i < N; i++) {
    int a, b;
    cin >> a >> b;
    --a, --b;
    g[a].emplace_back(b);
    g[b].emplace_back(a);
  }
  for(int i = 0; i < N; i++) {
    dfs(i, -1);
    rec(i, -1);
  }
  cout << ans << endl;
}
accuracy: 0.9555555555555556
time_ms: 4900
memory_kb: 81424
final_rank: 8

code_snippet: #include <bits/stdc++.h>

using namespace std;

int N;
vector< int > g[2000];
vector< int > ord;
int ans;
int dep[2000], upd[2000];

int dfs(int idx, int par) {
  dep[idx] = 0;
  for(auto to : g[idx]) {
    if(to == par) continue;
    dfs(to, idx);
    dep[idx] = max(dep[idx], dep[to] + 1);
  }
}

const int INF = 1 << 30;

bool memo2[2002][2002];
int dp2[2002][2002];

int rec3(int p, int q, int f = 0) {
  if(p >= q) return -INF;
  if(f >= 9 && memo2[ord[p]][ord[q]]) return dp2[ord[p]][ord[q]];
  if(f >= 9) {
    memo2[ord[p]][ord[q]] = true;
    return dp2[ord[p]][ord[q]] = max(upd[ord[q]], rec3(p, q - 1, true) + 1);
  }
  return max(upd[ord[q]], rec3(p, q - 1, f + 1) + 1);
}


bool memo3[2002][2002];
int dp3[2002][2002];

int rec4(int p, int q, int f = false) {
  if(p >= q) return -INF;
  if(f >= 9 && memo3[ord[p]][ord[q]]) return dp3[ord[p]][ord[q]];
  if(f >= 9) {
    memo3[ord[p]][ord[q]] = true;
    return dp3[ord[p]][ord[q]] = max(upd[ord[p]], rec4(p + 1, q, true) + 1);
  }
  return max(upd[ord[p]], rec4(p + 1, q, f + 1) + 1);
}


bool memo[2002][2002][2];
int dp[2002][2002][2];

int rec2(int p, int q, bool tern, int f = 0) {
  if(p >= q) return true;
  if(f >= 23 && memo[ord[p]][ord[q]][tern]) return dp[ord[p]][ord[q]][tern];

  bool ret = false;
  if(tern) {
    if(!rec2(p, q - 1, tern ^ 1, f + 1)) ret = true;
    if(upd[ord[q]] > rec4(p, q)) ret = true;
  } else {
    if(!rec2(p + 1, q, tern ^ 1, f + 1)) ret = true;
    if(upd[ord[p]] > rec3(p, q)) ret = true;
  }
  if(f >= 23) {
    memo[ord[p]][ord[q]][tern] = true;
    return dp[ord[p]][ord[q]][tern] = ret;
  }
  return ret;
}


int rec(int idx, int par) {
  ord.emplace_back(idx);
  pair< int, int > a(0, -1), b(0, -1);
  for(auto to : g[idx]) {
    if(to == par) continue;
    if(make_pair(dep[to] + 1, to) > a) {
      b = a;
      a = make_pair(dep[to] + 1, to);
    } else if(make_pair(dep[to] + 1, to) > b) {
      b = make_pair(dep[to] + 1, to);
    }
  }
  for(auto to : g[idx]) {
    if(to == par) continue;
    upd[idx] = a.second == to ? b.first : a.first;
    rec(to, idx);
  }
  upd[idx] = a.first;
  if(ord.size() >= 2 && rec2(0, ord.size() - 1, false)) {
    ++ans;
  }
  ord.pop_back();
}


int main() {
  cin >> N;
  for(int i = 1; i < N; i++) {
    int a, b;
    cin >> a >> b;
    --a, --b;
    g[a].emplace_back(b);
    g[b].emplace_back(a);
  }
  for(int i = 0; i < N; i++) {
    dfs(i, -1);
    rec(i, -1);
  }
  cout << ans << endl;
}
accuracy: 0.7555555555555555
time_ms: 1020
memory_kb: 32308
final_rank: 12

code_snippet: #include <bits/stdc++.h>

using namespace std;

int N;
vector< int > g[2000];
vector< int > ord;
int ans;
int dep[2000], upd[2000];

int dfs(int idx, int par) {
  dep[idx] = 0;
  for(auto to : g[idx]) {
    if(to == par) continue;
    dfs(to, idx);
    dep[idx] = max(dep[idx], dep[to] + 1);
  }
}

const int INF = 1 << 30;

bool memo2[2002][2002];
int dp2[2002][2002];

int rec3(int p, int q, int f = 0) {
  if(p >= q) return -INF;
  if(f >= 8 && memo2[ord[p]][ord[q]]) return dp2[ord[p]][ord[q]];
  if(f >= 8) {
    memo2[ord[p]][ord[q]] = true;
    return dp2[ord[p]][ord[q]] = max(upd[ord[q]], rec3(p, q - 1, true) + 1);
  }
  return max(upd[ord[q]], rec3(p, q - 1, f + 1) + 1);
}


bool memo3[2002][2002];
int dp3[2002][2002];

int rec4(int p, int q, int f = false) {
  if(p >= q) return -INF;
  if(f >= 8 && memo3[ord[p]][ord[q]]) return dp3[ord[p]][ord[q]];
  if(f >= 8) {
    memo3[ord[p]][ord[q]] = true;
    return dp3[ord[p]][ord[q]] = max(upd[ord[p]], rec4(p + 1, q, true) + 1);
  }
  return max(upd[ord[p]], rec4(p + 1, q, f + 1) + 1);
}


bool memo[2002][2002][2];
int dp[2002][2002][2];

int rec2(int p, int q, bool tern, int f = 0) {
  if(p >= q) return true;
  if(f >= 25 && memo[ord[p]][ord[q]][tern]) return dp[ord[p]][ord[q]][tern];

  bool ret = false;
  if(tern) {
    if(!rec2(p, q - 1, tern ^ 1, f + 1)) ret = true;
    if(upd[ord[q]] > rec4(p, q)) ret = true;
  } else {
    if(!rec2(p + 1, q, tern ^ 1, f + 1)) ret = true;
    if(upd[ord[p]] > rec3(p, q)) ret = true;
  }
  if(f >= 25) {
    memo[ord[p]][ord[q]][tern] = true;
    return dp[ord[p]][ord[q]][tern] = ret;
  }
  return ret;
}


int rec(int idx, int par) {
  ord.emplace_back(idx);
  vector< pair< int, int > > child;
  child.emplace_back(0, -1);
  for(auto to : g[idx]) {
    if(to == par) continue;
    child.emplace_back(dep[to] + 1, to);
  }
  sort(child.rbegin(), child.rend());
  for(auto to : g[idx]) {
    if(to == par) continue;
    upd[idx] = child[to == child[0].second].first;
    rec(to, idx);
  }
  upd[idx] = child[0].first;
  if(ord.size() >= 2 && rec2(0, ord.size() - 1, false)) {
    ++ans;
  }
  ord.pop_back();
}


int main() {
  cin >> N;
  for(int i = 1; i < N; i++) {
    int a, b;
    cin >> a >> b;
    --a, --b;
    g[a].emplace_back(b);
    g[b].emplace_back(a);
  }
  for(int i = 0; i < N; i++) {
    dfs(i, -1);
    rec(i, -1);
  }
  cout << ans << endl;
}
accuracy: 0.9555555555555556
time_ms: 4910
memory_kb: 81496
final_rank: 9

code_snippet: #include <bits/stdc++.h>

using namespace std;

int N;
vector< int > g[2000];
vector< int > ord;
int ans;
int dep[2000], upd[2000];

int dfs(int idx, int par) {
  dep[idx] = 0;
  for(auto to : g[idx]) {
    if(to == par) continue;
    dfs(to, idx);
    dep[idx] = max(dep[idx], dep[to] + 1);
  }
}

const int INF = 1 << 30;

bool memo2[2002][2002];
int dp2[2002][2002];

int rec3(int p, int q, int f = 0) {
  if(p >= q) return -INF;
  if(f >= 10 && memo2[ord[p]][ord[q]]) return dp2[ord[p]][ord[q]];
  if(f >= 10) {
    memo2[ord[p]][ord[q]] = true;
    return dp2[ord[p]][ord[q]] = max(upd[ord[q]], rec3(p, q - 1, true) + 1);
  }
  return max(upd[ord[q]], rec3(p, q - 1, f + 1) + 1);
}


bool memo3[2002][2002];
int dp3[2002][2002];

int rec4(int p, int q, int f = false) {
  if(p >= q) return -INF;
  if(f >= 10 && memo3[ord[p]][ord[q]]) return dp3[ord[p]][ord[q]];
  if(f >= 10) {
    memo3[ord[p]][ord[q]] = true;
    return dp3[ord[p]][ord[q]] = max(upd[ord[p]], rec4(p + 1, q, true) + 1);
  }
  return max(upd[ord[p]], rec4(p + 1, q, f + 1) + 1);
}


bool memo[2002][2002][2];
int dp[2002][2002][2];

int rec2(int p, int q, bool tern, int f = 0) {
  if(p >= q) return true;
  if(f >= 20 && memo[ord[p]][ord[q]][tern]) return dp[ord[p]][ord[q]][tern];

  bool ret = false;
  if(tern) {
    if(!rec2(p, q - 1, tern ^ 1, f + 1)) ret = true;
    if(upd[ord[q]] > rec4(p, q)) ret = true;
  } else {
    if(!rec2(p + 1, q, tern ^ 1, f + 1)) ret = true;
    if(upd[ord[p]] > rec3(p, q)) ret = true;
  }
  if(f >= 20) {
    memo[ord[p]][ord[q]][tern] = true;
    return dp[ord[p]][ord[q]][tern] = ret;
  }
  return ret;
}


int rec(int idx, int par) {
  ord.emplace_back(idx);
  vector< pair< int, int > > child;
  child.emplace_back(0, -1);
  for(auto to : g[idx]) {
    if(to == par) continue;
    child.emplace_back(dep[to] + 1, to);
  }
  sort(child.rbegin(), child.rend());
  for(auto to : g[idx]) {
    if(to == par) continue;
    upd[idx] = child[to == child[0].second].first;
    rec(to, idx);
  }
  upd[idx] = child[0].first;
  if(ord.size() >= 2 && rec2(0, ord.size() - 1, false)) {
    ++ans;
  }
  ord.pop_back();
}


int main() {
  cin >> N;
  for(int i = 1; i < N; i++) {
    int a, b;
    cin >> a >> b;
    --a, --b;
    g[a].emplace_back(b);
    g[b].emplace_back(a);
  }
  for(int i = 0; i < N; i++) {
    dfs(i, -1);
    rec(i, -1);
  }
  cout << ans << endl;
}
accuracy: 0.7555555555555555
time_ms: 1210
memory_kb: 32552
final_rank: 13

code_snippet: #include <bits/stdc++.h>

using namespace std;

int N;
vector< int > g[2000];
vector< int > ord;
int ans;
int dep[2000], upd[2000];

int dfs(int idx, int par) {
  dep[idx] = 0;
  for(auto to : g[idx]) {
    if(to == par) continue;
    dfs(to, idx);
    dep[idx] = max(dep[idx], dep[to] + 1);
  }
}

const int INF = 1 << 30;

bool memo2[2002][2002];
int dp2[2002][2002];

int rec3(int p, int q, int f = 0) {
  if(p >= q) return -INF;
  if(f >= 4 && memo2[ord[p]][ord[q]]) return dp2[ord[p]][ord[q]];
  if(f >= 4) {
    memo2[ord[p]][ord[q]] = true;
    return dp2[ord[p]][ord[q]] = max(upd[ord[q]], rec3(p, q - 1, true) + 1);
  }
  return max(upd[ord[q]], rec3(p, q - 1, f + 1) + 1);
}


bool memo3[2002][2002];
int dp3[2002][2002];

int rec4(int p, int q, int f = false) {
  if(p >= q) return -INF;
  if(f >= 4 && memo3[ord[p]][ord[q]]) return dp3[ord[p]][ord[q]];
  if(f >= 4) {
    memo3[ord[p]][ord[q]] = true;
    return dp3[ord[p]][ord[q]] = max(upd[ord[p]], rec4(p + 1, q, true) + 1);
  }
  return max(upd[ord[p]], rec4(p + 1, q, f + 1) + 1);
}


bool memo[2002][2002][2];
int dp[2002][2002][2];

int rec2(int p, int q, bool tern) {
  if(p >= q) return true;
  //if(memo[ord[p]][ord[q]][tern]) return dp[ord[p]][ord[q]][tern];

  bool ret = false;
  if(tern) {
    if(!rec2(p, q - 1, tern ^ 1)) return true;
    if(upd[ord[q]] > rec4(p, q)) return true;
  } else {
    if(!rec2(p + 1, q, tern ^ 1)) return true;
    if(upd[ord[p]] > rec3(p, q)) return true;
  }
  return false;
}


int rec(int idx, int par) {
  ord.emplace_back(idx);
  vector< pair< int, int > > child;
  child.emplace_back(0, -1);
  for(auto to : g[idx]) {
    if(to == par) continue;
    child.emplace_back(dep[to] + 1, to);
  }
  sort(child.rbegin(), child.rend());
  for(auto to : g[idx]) {
    if(to == par) continue;
    upd[idx] = child[to == child[0].second].first;
    rec(to, idx);
  }
  upd[idx] = child[0].first;
  if(ord.size() >= 2 && rec2(0, ord.size() - 1, false)) {
    ++ans;
  }
  ord.pop_back();
}


int main() {
  cin >> N;
  for(int i = 1; i < N; i++) {
    int a, b;
    cin >> a >> b;
    --a, --b;
    g[a].emplace_back(b);
    g[b].emplace_back(a);
  }
  for(int i = 0; i < N; i++) {
    dfs(i, -1);
    rec(i, -1);
  }
  cout << ans << endl;
}
accuracy: 0.8
time_ms: 680
memory_kb: 32252
final_rank: 10

code_snippet: #include <bits/stdc++.h>

using namespace std;

int N;
vector< int > g[2000];
vector< int > ord;
int ans;
int dep[2000], upd[2000];

int dfs(int idx, int par) {
  dep[idx] = 0;
  for(auto to : g[idx]) {
    if(to == par) continue;
    dfs(to, idx);
    dep[idx] = max(dep[idx], dep[to] + 1);
  }
}

const int INF = 1 << 30;

bool memo2[2002][2002];
int dp2[2002][2002];

int rec3(int p, int q, int f = 0) {
  if(p >= q) return -INF;
  if(f >= 3 && memo2[ord[p]][ord[q]]) return dp2[ord[p]][ord[q]];
  if(f >= 3) {
    memo2[ord[p]][ord[q]] = true;
    return dp2[ord[p]][ord[q]] = max(upd[ord[q]], rec3(p, q - 1, true) + 1);
  }
  return max(upd[ord[q]], rec3(p, q - 1, f + 1) + 1);
}


bool memo3[2002][2002];
int dp3[2002][2002];

int rec4(int p, int q, int f = false) {
  if(p >= q) return -INF;
  if(f >= 3 && memo3[ord[p]][ord[q]]) return dp3[ord[p]][ord[q]];
  if(f >= 3) {
    memo3[ord[p]][ord[q]] = true;
    return dp3[ord[p]][ord[q]] = max(upd[ord[p]], rec4(p + 1, q, true) + 1);
  }
  return max(upd[ord[p]], rec4(p + 1, q, f + 1) + 1);
}


bool memo[2002][2002][2];
int dp[2002][2002][2];

int rec2(int p, int q, bool tern) {
  if(p >= q) return true;
  //if(memo[ord[p]][ord[q]][tern]) return dp[ord[p]][ord[q]][tern];

  bool ret = false;
  if(tern) {
    if(!rec2(p, q - 1, tern ^ 1)) return true;
    if(upd[ord[q]] > rec4(p, q)) return true;
  } else {
    if(!rec2(p + 1, q, tern ^ 1)) return true;
    if(upd[ord[p]] > rec3(p, q)) return true;
  }
  return false;
}


int rec(int idx, int par) {
  ord.emplace_back(idx);
  vector< pair< int, int > > child;
  child.emplace_back(0, -1);
  for(auto to : g[idx]) {
    if(to == par) continue;
    child.emplace_back(dep[to] + 1, to);
  }
  sort(child.rbegin(), child.rend());
  for(auto to : g[idx]) {
    if(to == par) continue;
    upd[idx] = child[to == child[0].second].first;
    rec(to, idx);
  }
  upd[idx] = child[0].first;
  if(ord.size() >= 2 && rec2(0, ord.size() - 1, false)) {
    ++ans;
  }
  ord.pop_back();
}


int main() {
  cin >> N;
  for(int i = 1; i < N; i++) {
    int a, b;
    cin >> a >> b;
    --a, --b;
    g[a].emplace_back(b);
    g[b].emplace_back(a);
  }
  for(int i = 0; i < N; i++) {
    dfs(i, -1);
    rec(i, -1);
  }
  cout << ans << endl;
}
accuracy: 0.7555555555555555
time_ms: 650
memory_kb: 32456
final_rank: 11

code_snippet: #include <bits/stdc++.h>

using namespace std;
using ll = long long;
using ull = unsigned long long;
template <class T> using V = vector<T>;
template <class T> using VV = V<V<T>>;
constexpr ll TEN(int n) { return (n == 0) ? 1 : 10 * TEN(n - 1); }

using P = pair<int, int>;

VV<int> g;
VV<int> near;
VV<V<P>> top2; //(id, length)

V<P> buf;
void unique(V<P>& v) {
    sort(v.begin(), v.end(), [&](P a, P b) {
        if (a.first != b.first) return a.first < b.first;
        return a.second > b.second;
    });
    v.erase(unique(v.begin(), v.end(), [&](P a, P b) {
        return a.first == b.first;
    }), v.end());
    sort(v.begin(), v.end(), [&](P a, P b) {
        return a.second > b.second;
    });
    if (v.size() > 2) v.resize(2);
}

void dfs(int p, int b, int rt, int cr, int ndp) {
    near[rt][p] = cr;
    top2[rt][p].insert(top2[rt][p].end(), buf.begin(), buf.end());
    unique(top2[rt][p]);

    buf.push_back({cr, ndp});
    unique(buf);

    for (int d: g[p]) {
        if (d == b) continue;
        dfs(d, p, rt, cr, ndp + 1);
    }
}

VV<int> to_id;

VV<bool> vis;
VV<bool> dp;

bool solve(int p, int bp, int q, int bq) {
    int id1 = to_id[p][bp], id2 = to_id[q][bq];
    if (vis[id1][id2]) return dp[id1][id2];
    vis[id1][id2] = true;

    int da = -1, db = -1;
    for (auto pi: top2[p][near[p][q]]) {
        if (pi.first == bp) continue;
        da = max(da, pi.second);
    }
    for (auto pi: top2[q][p]) {
        if (pi.first == bq) continue;
        db = max(db, pi.second);
    }
    if (da > db) return dp[id1][id2] = true;
    if (near[p][q] == q) return dp[id1][id2] = false;
    return dp[id1][id2] = !solve(q, bq, near[p][q], p);
}

int main() {
    int n;
    cin >> n;
    g = VV<int>(n);
    for (int i = 0; i < n - 1; i++) {
        int a, b;
        cin >> a >> b; a--; b--;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    near = VV<int>(n, V<int>(n, -1));
    top2 = VV<V<P>>(n, VV<P>(n));
    for (int s = 0; s < n; s++) {
        buf.clear();
        for (int d: g[s]) {
            dfs(d, s, s, d, 1);
        }
        for (int i = 0; i < n; i++) {
            reverse(g[i].begin(), g[i].end());
        }
        buf.clear();
        for (int d: g[s]) {
            dfs(d, s, s, d, 1);
        }
    }

    to_id = VV<int>(n, V<int>(n + 1, -1));
    int idc = 0;
    for (int i = 0; i < n; i++) {
        for (int j: g[i]) {
            to_id[i][j] = idc++;
        }
        to_id[i][n] = idc++;
    }

    vis = VV<bool>(idc, V<bool>(idc));
    dp = VV<bool>(idc, V<bool>(idc));

    int ans = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (i == j) continue;
            ans += solve(i, n, j, n);
        }
    }

    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 2160
memory_kb: 293268
final_rank: 5

code_snippet: #include <bits/stdc++.h>
#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,NAME,...) NAME
#define pr(...) cerr<< GET_MACRO(__VA_ARGS__,pr8,pr7,pr6,pr5,pr4,pr3,pr2,pr1)(__VA_ARGS__) <<endl
#define pr1(a) (#a)<<"="<<(a)<<" "
#define pr2(a,b) pr1(a)<<pr1(b)
#define pr3(a,b,c) pr1(a)<<pr2(b,c)
#define pr4(a,b,c,d) pr1(a)<<pr3(b,c,d)
#define pr5(a,b,c,d,e) pr1(a)<<pr4(b,c,d,e)
#define pr6(a,b,c,d,e,f) pr1(a)<<pr5(b,c,d,e,f)
#define pr7(a,b,c,d,e,f,g) pr1(a)<<pr6(b,c,d,e,f,g)
#define pr8(a,b,c,d,e,f,g,h) pr1(a)<<pr7(b,c,d,e,f,g,h)
#define prArr(a) {cerr<<(#a)<<"={";int i=0;for(auto t:(a))cerr<<(i++?", ":"")<<t;cerr<<"}"<<endl;}
using namespace std;
using Int = long long;
using _int = int;
using ll = long long;
using Double = long double;
const Int INF = (1LL<<60)+1e9; // ~ 1.15 * 1e18
const Int mod = (1e9)+7;
const Double EPS = 1e-8;
const Double PI = 6.0 * asin((Double)0.5);
using P = pair<Int,Int>;
template<class T> T Max(T &a,T b){return a=max(a,b);}
template<class T> T Min(T &a,T b){return a=min(a,b);}
template<class T1, class T2> ostream& operator<<(ostream& o,pair<T1,T2> p){return o<<"("<<p.first<<","<<p.second<<")";}
template<class T1, class T2, class T3> ostream& operator<<(ostream& o,tuple<T1,T2,T3> t){
  return o<<"("<<get<0>(t)<<","<<get<1>(t)<<","<<get<2>(t)<<")";}
template<class T1, class T2> istream& operator>>(istream& i,pair<T1,T2> &p){return i>>p.first>>p.second;}
template<class T> ostream& operator<<(ostream& o,vector<T> a){Int i=0;for(T t:a)o<<(i++?" ":"")<<t;return o;}
template<class T> istream& operator>>(istream& i,vector<T> &a){for(T &t:a)i>>t;return i;}
//INSERT ABOVE HERE

class TreeParent{
public:
  int V;                        //ノード数
  int root;                     //根
  vector<vector<int> > G;       //Graph
  vector<int> parent;           //親
  int ok;
  TreeParent():V(-1){};
  TreeParent(int V,int root = 0):V(V),root(root),G(V),parent(V),ok(0){}
  TreeParent(vector<vector<int> > &G,int root = 0):V(G.size()),root(root),G(G),parent(V),ok(0){}
  void resize(int n){*this = TreeParent(n);}
  void add_edge(int a,int b){
    ok = false;
    assert(a < V && b < V);
    assert(a >= 0 && b >= 0);
    G[a].push_back(b);
    G[b].push_back(a);
  }
  void build(int root = -1){
    ok = 1;
    if(root != -1) this->root = root;
    function<void(int,int)> dfs = [&](int pos,int pre){
      parent[pos] = pre;
      for(int to:G[pos]) if(to != pre) dfs(to, pos);
    };
    dfs(this->root, -1);
  }
  inline int get(int u){/*assert(ok); assert(0 <= u && u < V)*/; return parent[u];}
  
};

const int MAX_N = 2010;
int N;
vector<vector<int> > G;
vector<vector<int> > edge;
vector<TreeParent> tp;
vector<vector<P> > path;

void buildPath(){
  function<int(int, int)> dfs = [&](int pos, int par){
    int res = 0;
    for(int to:G[pos])
      if( to != par) Max(res, dfs(to, pos) + 1);
    return res;
  };

  path.resize(N);
  for(int i=0;i<N;i++){
    vector<P> res = {P(0, -2), P(0, -2), P(0, -2)};
    for(int to:G[i]){
      int len = dfs(to, i) + 1;
      res.push_back(P(len, to));
      sort(res.begin(), res.end(), greater<P>());
      while((int)res.size() > 3) res.pop_back();
    }
    path[i] = res;
  }
}

int getMaxPath2(int pos,int ng1,int ng2){
  //if(ng1 != -1) assert(edge[pos][ng1] != -1);
  //if(ng2 != -1) assert(edge[pos][ng2] != -1);
  for(auto &p:path[pos]){
    int len, to; tie(len, to) = p;
    if(to != ng1 && to != ng2) return len;
  }
  assert(0);
}

//posが動く ng1とng2以外のノードを通っていく最大のパス
int getMaxPath(int pos, int par, int ng2){
  static _int used[2][MAX_N][MAX_N], mem[2][MAX_N][MAX_N];
  //assert(ng2 != -1);
  if(pos == par || pos == ng2) return -1;
  int a = par==-1? pos:edge[par][pos];
  int b = edge[tp[pos].get(ng2)][ng2];
  int t = par != -1;
  
  //  assert(a >= 0 && b >= 0);
  if(used[t][a][b]++) return mem[t][a][b];
  int m = tp[ng2].get(pos); 
  int p = getMaxPath(m, pos, ng2) + 1; //ng2の方に近づく
  int q = getMaxPath2(pos, par, m); //それ以外
  int res = max(p, q);
  return mem[t][a][b] = res;
}

int dfs(int a,int b, int turn, int pa, int pb){
  static bool used[2][4][MAX_N][MAX_N], mem[2][4][MAX_N][MAX_N];
  int idxa = pa==-1? a:edge[a][pa];
  int idxb = pb==-1? b:edge[b][pb];
  int t = (pa == -1) + 2*(pb == -1);
  //assert(idxa >= 0 && idxb >= 0);
  if(a == b) return turn;
  if(used[turn][t][idxa][idxb]) return mem[turn][t][idxa][idxb];
  used[turn][t][idxa][idxb] = 1;

  int res = 0;
  if(turn == 0){
    int atob = tp[b].get(a);
    int A = getMaxPath(a, pa, atob); //折り返す。
    int B = getMaxPath(b, pb, a);//bに近づく
    if(A > B) res = 0;
    else res = dfs(atob, b, !turn, a, pb);
  }

  if(turn == 1){
    int btoa = tp[a].get(b);
    int B = getMaxPath(b, pb, btoa);//折り返す
    int A = getMaxPath(a, pa, b);//aに近づく
    if(B > A) res = 1;
    else res = dfs(a, btoa, !turn, pa, b);
  }
  return mem[turn][t][idxa][idxb] = res;
};

signed main(){
  srand((unsigned)time(NULL));
  cin.tie(0);
  ios_base::sync_with_stdio(0);
  cout << fixed << setprecision(12);

  cin>>N;
  G.resize(N);
  edge.resize(N, vector<int>(N, -1));
  
  for(int i=0;i<N-1;i++){
    int a, b;
    cin>>a>>b; a--,b--;
    G[a].push_back(b);
    G[b].push_back(a);
    edge[a][b] = i;
    edge[b][a] = i;
  }

  tp.resize(N);
  for(int i=0;i<N;i++) tp[i] = TreeParent(G), tp[i].build(i);
  buildPath();
  
  int ans = 0;
  for(int i=0;i<N;i++)
    for(int j=0;j<N;j++){
      if(i == j) continue;
      int win = dfs(i, j, 0, -1, -1) == 0;
      //if(win==0) cout<<"lose: "<<i+1<<" "<<j+1<<endl;
      ans += win;
    }
  cout<<ans<<endl;
  
  return 0;
}
accuracy: 1
time_ms: 2980
memory_kb: 351624
final_rank: 6

code_snippet: #include<iomanip>
#include<limits>
#include<thread>
#include<utility>
#include<iostream>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<numeric>
#include<cassert>
#include<random>
#include<chrono>
#include<unordered_set>
#include<unordered_map>
#include<fstream>
#include<list>
#include<functional>
#include<bitset>
#include<complex>
#include<tuple>
using namespace std;
typedef unsigned long long int ull;
typedef long long int ll;
typedef pair<ll,ll> pll;
typedef pair<int,int> pi;
typedef pair<double,double> pd;
typedef pair<double,ll> pdl;
#define F first
#define S second
const ll E=1e18+7;
const ll MOD=1000000007;

const ll N_MAX=2000;


ll n;
vector<ll> edge[N_MAX];
pll MX[N_MAX][3];
ll parent[N_MAX];
ll NEXT[N_MAX][N_MAX];
pll EDGE[N_MAX][N_MAX][2];
vector<ll> children[N_MAX];
pll RMQ[N_MAX][N_MAX];
int ans[N_MAX][N_MAX][4];


pll dfs1(ll w,ll p){
    parent[w]=p;
    MX[w][0]=MX[w][1]=MX[w][2]={0,w};
    for(auto &I:edge[w]){
        if(I==p){continue;}
        pll ret=dfs1(I,w);
        if(ret>MX[w][2]){MX[w][2]=ret;}
        if(MX[w][2]>MX[w][1]){swap(MX[w][1],MX[w][2]);}
        if(MX[w][1]>MX[w][0]){swap(MX[w][0],MX[w][1]);}
    }
    return {MX[w][0].F+1,w};
}

void merge(ll w,ll c){
    for(auto &I:children[c]){
        NEXT[w][I]=c;
        NEXT[I][w]=parent[I];
        if(MX[w][0].S==NEXT[w][I]){
            EDGE[w][I][0]=MX[w][1];
            EDGE[w][I][1]=MX[w][2];
        }
        else if(MX[w][1].S==NEXT[w][I]){
            EDGE[w][I][0]=MX[w][0];
            EDGE[w][I][1]=MX[w][2];
        }
        else{
            EDGE[w][I][0]=MX[w][0];
            EDGE[w][I][1]=MX[w][1];
        }
        if(MX[I][0].S==NEXT[I][w]){
            EDGE[I][w][0]=MX[I][1];
            EDGE[I][w][1]=MX[I][2];
        }
        else if(MX[I][1].S==NEXT[I][w]){
            EDGE[I][w][0]=MX[I][0];
            EDGE[I][w][1]=MX[I][2];
        }
        else{
            EDGE[I][w][0]=MX[I][0];
            EDGE[I][w][1]=MX[I][1];
        }
    }
    for(int i=1;i<children[w].size();i++){
        ll I=children[w][i];
        for(auto &T:children[c]){
            NEXT[I][T]=parent[I];
            NEXT[T][I]=parent[T];
            if(MX[I][0].S==NEXT[I][T]){
                EDGE[I][T][0]=MX[I][1];
                EDGE[I][T][1]=MX[I][2];
            }
            else if(MX[I][1].S==NEXT[I][T]){
                EDGE[I][T][0]=MX[I][0];
                EDGE[I][T][1]=MX[I][2];
            }
            else{
                EDGE[I][T][0]=MX[I][0];
                EDGE[I][T][1]=MX[I][1];
            }
            if(MX[T][0].S==NEXT[T][I]){
                EDGE[T][I][0]=MX[T][1];
                EDGE[T][I][1]=MX[T][2];
            }
            else if(MX[T][1].S==NEXT[T][I]){
                EDGE[T][I][0]=MX[T][0];
                EDGE[T][I][1]=MX[T][2];
            }
            else{
                EDGE[T][I][0]=MX[T][0];
                EDGE[T][I][1]=MX[T][1];
            }
        }
    }
    for(auto &I:children[c]){
        children[w].push_back(I);
    }
}

void dfs2(ll w,ll p,ll pn){
    if(MX[w][2].F<pn){MX[w][2]={pn,p};}
    if(MX[w][2]>MX[w][1]){swap(MX[w][1],MX[w][2]);}
    if(MX[w][1]>MX[w][0]){swap(MX[w][0],MX[w][1]);}
    children[w].push_back(w);
    for(auto &I:edge[w]){
        if(I==p){continue;}
        if(I==MX[w][0].S){
            dfs2(I,w,max(pn+1,MX[w][1].F+1));
        }
        else{
            dfs2(I,w,max(pn+1,MX[w][0].F+1));
        }
        merge(w,I);
    }
}

ll rmq(ll s,ll t){
    assert(s!=t);
    if(RMQ[s][t].F!=-1){return RMQ[s][t].F;}
    if(NEXT[s][t]==t){RMQ[s][t]={0,1}; return RMQ[s][t].F;}
    rmq(NEXT[s][t],t);
    RMQ[s][t]=RMQ[NEXT[s][t]][t];
    if(EDGE[NEXT[s][t]][s][0].S==NEXT[NEXT[s][t]][t]){
        RMQ[s][t].F=max(RMQ[s][t].F,EDGE[NEXT[s][t]][s][1].F+RMQ[s][t].S);
    }
    else{
        RMQ[s][t].F=max(RMQ[s][t].F,EDGE[NEXT[s][t]][s][0].F+RMQ[s][t].S);
    }
    RMQ[s][t].S++;
    return RMQ[s][t].F;
}


//1::使っても良い 0::使ってはだめ from,to
int Ans(ll s,ll t,int k){
    assert(s!=t);
    if(ans[s][t][k]!=-1){return ans[s][t][k];}
    if(k==3){
        if(NEXT[s][t]==t){return ans[s][t][k]=(EDGE[s][t][0].F>EDGE[t][s][0].F);}
        if(EDGE[s][t][0].F>max(rmq(s,t),EDGE[t][s][0].F)){return ans[s][t][k]=1;}
        if(EDGE[NEXT[s][t]][t][0].S==s){
            return ans[s][t][k]=!Ans(t,NEXT[s][t],2);
        }
        return ans[s][t][k]=!Ans(t,NEXT[s][t],3);
    }
    else if(k==2){
        if(NEXT[s][t]==t){return ans[s][t][k]=(EDGE[s][t][0].F>EDGE[t][s][1].F);}
        if(EDGE[s][t][0].F>max(rmq(s,t),EDGE[t][s][1].F)){return ans[s][t][k]=1;}
        if(EDGE[NEXT[s][t]][t][0].S==s){
            return ans[s][t][k]=!Ans(t,NEXT[s][t],0);
        }
        return ans[s][t][k]=!Ans(t,NEXT[s][t],1);
    }
    else if(k==1){
        if(NEXT[s][t]==t){return ans[s][t][k]=(EDGE[s][t][1].F>EDGE[t][s][0].F);}
        if(EDGE[s][t][1].F>max(rmq(s,t),EDGE[t][s][0].F)){return ans[s][t][k]=1;}
        if(EDGE[NEXT[s][t]][t][0].S==s){
            return ans[s][t][k]=!Ans(t,NEXT[s][t],2);
        }
        return ans[s][t][k]=!Ans(t,NEXT[s][t],3);
    }
    if(NEXT[s][t]==t){return ans[s][t][k]=(EDGE[s][t][1].F>EDGE[t][s][1].F);}
    if(EDGE[s][t][1].F>max(rmq(s,t),EDGE[t][s][1].F)){return ans[s][t][k]=1;}
    if(EDGE[NEXT[s][t]][t][0].S==s){
        return ans[s][t][k]=!Ans(t,NEXT[s][t],0);
    }
    return ans[s][t][k]=!Ans(t,NEXT[s][t],1);
}



int main(){
    cin.tie(0);
    ios_base::sync_with_stdio(0);
    cin>>n;
    for(auto &I:RMQ){
        for(auto &T:I){T={-1,-1};}
    }
    for(auto &I:ans){
        for(auto &T:I){
            for(auto &H:T){H=-1;}
        }
    }
    for(int i=1;i<n;i++){
        ll a,b;
        cin>>a>>b;
        a--; b--;
        edge[a].push_back(b);
        edge[b].push_back(a);
    }
    dfs1(0,-1);
    dfs2(0,-1,0);
    ll cnt=0;
    for(int i=0;i<n;i++){
        for(int t=0;t<n;t++){
            if(i==t){continue;}
            //if(Ans(i,t,3)){cout<<i+1<<" "<<t+1<<endl;}
            if(Ans(i,t,3)){cnt++;}
        }
    }
    cout<<cnt<<endl;
    
    
    return 0;
}
accuracy: 1
time_ms: 1100
memory_kb: 297576
final_rank: 4

code_snippet: #include <bits/stdc++.h>
#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,NAME,...) NAME
#define pr(...) cerr<< GET_MACRO(__VA_ARGS__,pr8,pr7,pr6,pr5,pr4,pr3,pr2,pr1)(__VA_ARGS__) <<endl
#define pr1(a) (#a)<<"="<<(a)<<" "
#define pr2(a,b) pr1(a)<<pr1(b)
#define pr3(a,b,c) pr1(a)<<pr2(b,c)
#define pr4(a,b,c,d) pr1(a)<<pr3(b,c,d)
#define pr5(a,b,c,d,e) pr1(a)<<pr4(b,c,d,e)
#define pr6(a,b,c,d,e,f) pr1(a)<<pr5(b,c,d,e,f)
#define pr7(a,b,c,d,e,f,g) pr1(a)<<pr6(b,c,d,e,f,g)
#define pr8(a,b,c,d,e,f,g,h) pr1(a)<<pr7(b,c,d,e,f,g,h)
#define prArr(a) {cerr<<(#a)<<"={";int i=0;for(auto t:(a))cerr<<(i++?", ":"")<<t;cerr<<"}"<<endl;}
using namespace std;
using Int = long long;
using _int = int;
using ll = long long;
using Double = long double;
const Int INF = (1LL<<60)+1e9; // ~ 1.15 * 1e18
const Int mod = (1e9)+7;
const Double EPS = 1e-8;
const Double PI = 6.0 * asin((Double)0.5);
using P = pair<Int,Int>;
template<class T> T Max(T &a,T b){return a=max(a,b);}
template<class T> T Min(T &a,T b){return a=min(a,b);}
template<class T1, class T2> ostream& operator<<(ostream& o,pair<T1,T2> p){return o<<"("<<p.first<<","<<p.second<<")";}
template<class T1, class T2, class T3> ostream& operator<<(ostream& o,tuple<T1,T2,T3> t){
  return o<<"("<<get<0>(t)<<","<<get<1>(t)<<","<<get<2>(t)<<")";}
template<class T1, class T2> istream& operator>>(istream& i,pair<T1,T2> &p){return i>>p.first>>p.second;}
template<class T> ostream& operator<<(ostream& o,vector<T> a){Int i=0;for(T t:a)o<<(i++?" ":"")<<t;return o;}
template<class T> istream& operator>>(istream& i,vector<T> &a){for(T &t:a)i>>t;return i;}
//INSERT ABOVE HERE

class TreeParent{
public:
  int V;                        //ノード数
  int root;                     //根
  vector<vector<int> > G;       //Graph
  vector<int> parent;           //親
  int ok;
  TreeParent():V(-1){};
  TreeParent(int V,int root = 0):V(V),root(root),G(V),parent(V),ok(0){}
  TreeParent(vector<vector<int> > &G,int root = 0):V(G.size()),root(root),G(G),parent(V),ok(0){}
  void resize(int n){*this = TreeParent(n);}
  void add_edge(int a,int b){
    ok = false;
    assert(a < V && b < V);
    assert(a >= 0 && b >= 0);
    G[a].push_back(b);
    G[b].push_back(a);
  }
  void build(int root = -1){
    ok = 1;
    if(root != -1) this->root = root;
    function<void(int,int)> dfs = [&](int pos,int pre){
      parent[pos] = pre;
      for(int to:G[pos]) if(to != pre) dfs(to, pos);
    };
    dfs(this->root, -1);
  }
  inline int get(int u){/*assert(ok); assert(0 <= u && u < V)*/; return parent[u];}
  
};

const int MAX_N = 2010;
int N;
vector<vector<int> > G;
vector<vector<int> > edge;
vector<TreeParent> tp;
vector<vector<P> > path;

void buildPath(){
  function<int(int, int)> dfs = [&](int pos, int par){
    int res = 0;
    for(int to:G[pos])
      if( to != par) Max(res, dfs(to, pos) + 1);
    return res;
  };

  path.resize(N);
  for(int i=0;i<N;i++){
    vector<P> res = {P(0, -2), P(0, -2), P(0, -2)};
    for(int to:G[i]){
      int len = dfs(to, i) + 1;
      res.push_back(P(len, to));
      sort(res.begin(), res.end(), greater<P>());
      while(res.size() > 3) res.pop_back();
    }
    path[i] = res;
  }
}

int getMaxPath2(int pos,int ng1,int ng2){
  //if(ng1 != -1) assert(edge[pos][ng1] != -1);
  //if(ng2 != -1) assert(edge[pos][ng2] != -1);
  for(auto &p:path[pos]){
    int len, to; tie(len, to) = p;
    if(to != ng1 && to != ng2) return len;
  }
  assert(0);
}

//posが動く ng1とng2以外のノードを通っていく最大のパス
int getMaxPath(int pos, int par, int ng2){
  static _int used[MAX_N][MAX_N][2], mem[MAX_N][MAX_N][2];
  //assert(ng2 != -1);
  if(pos == par || pos == ng2) return -1;
  int a = par==-1? pos:edge[par][pos];
  int b = edge[tp[pos].get(ng2)][ng2];
  int t = par != -1;
  
  //  assert(a >= 0 && b >= 0);
  if(used[a][b][t]++) return mem[a][b][t];
  int m = tp[ng2].get(pos); 
  int p = getMaxPath(m, pos, ng2) + 1; //ng2の方に近づく
  int q = getMaxPath2(pos, par, m); //それ以外
  int res = max(p, q);
  return mem[a][b][t] = res;
}

int dfs(int a,int b, int turn, int pa, int pb){
  static bool used[MAX_N][MAX_N][2][4], mem[MAX_N][MAX_N][2][4];
  int idxa = pa==-1? a:edge[a][pa];
  int idxb = pb==-1? b:edge[b][pb];
  int t = (pa == -1) + 2*(pb == -1);
  //assert(idxa >= 0 && idxb >= 0);
  if(a == b) return turn;
  if(used[idxa][idxb][turn][t]) return mem[idxa][idxb][turn][t];
  used[idxa][idxb][turn][t] = 1;

  int res = 0;
  if(turn == 0){
    int atob = tp[b].get(a);
    int A = getMaxPath(a, pa, atob); //折り返す。
    int B = getMaxPath(b, pb, a);//bに近づく
    if(A > B) res = 0;
    else res = dfs(atob, b, !turn, a, pb);
  }

  if(turn == 1){
    int btoa = tp[a].get(b);
    int B = getMaxPath(b, pb, btoa);//折り返す
    int A = getMaxPath(a, pa, b);//aに近づく
    if(B > A) res = 1;
    else res = dfs(a, btoa, !turn, pa, b);
  }
  return mem[idxa][idxb][turn][t] = res;
};

signed main(){
  srand((unsigned)time(NULL));
  cin.tie(0);
  ios_base::sync_with_stdio(0);
  cout << fixed << setprecision(12);

  cin>>N;
  G.resize(N);
  edge.resize(N, vector<int>(N, -1));
  
  for(int i=0;i<N-1;i++){
    int a, b;
    cin>>a>>b; a--,b--;
    G[a].push_back(b);
    G[b].push_back(a);
    edge[a][b] = i;
    edge[b][a] = i;
  }

  tp.resize(N);
  for(int i=0;i<N;i++) tp[i] = TreeParent(G), tp[i].build(i);
  buildPath();
  
  int ans = 0;
  for(int i=0;i<N;i++)
    for(int j=0;j<N;j++){
      if(i == j) continue;
      int win = dfs(i, j, 0, -1, -1) == 0;
      //if(win==0) cout<<"lose: "<<i+1<<" "<<j+1<<endl;
      ans += win;
    }
  cout<<ans<<endl;
  
  return 0;
}
accuracy: 1
time_ms: 3090
memory_kb: 394660
final_rank: 7

code_snippet: #include<iomanip>
#include<limits>
#include<thread>
#include<utility>
#include<iostream>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<numeric>
#include<cassert>
#include<random>
#include<chrono>
#include<unordered_set>
#include<unordered_map>
#include<fstream>
#include<list>
#include<functional>
#include<bitset>
#include<complex>
#include<tuple>
using namespace std;
typedef unsigned long long int ull;
//typedef long long int ll;
typedef int ll;
typedef pair<ll,ll> pll;
typedef pair<int,int> pi;
typedef pair<double,double> pd;
typedef pair<double,ll> pdl;
#define F first
#define S second
//const ll E=1e18+7;
const ll MOD=1000000007;

const ll N_MAX=2000;


ll n;
vector<ll> edge[N_MAX];
pll MX[N_MAX][3];
ll parent[N_MAX];
ll NEXT[N_MAX][N_MAX];
vector<ll> children[N_MAX];
pll RMQ[N_MAX][N_MAX];
bool ans[N_MAX][N_MAX][4];


pll dfs1(ll w,ll p){
    parent[w]=p;
    MX[w][0]=MX[w][1]=MX[w][2]={0,w};
    for(auto &I:edge[w]){
        if(I==p){continue;}
        pll ret=dfs1(I,w);
        if(ret>MX[w][2]){MX[w][2]=ret;}
        if(MX[w][2]>MX[w][1]){swap(MX[w][1],MX[w][2]);}
        if(MX[w][1]>MX[w][0]){swap(MX[w][0],MX[w][1]);}
    }
    return {MX[w][0].F+1,w};
}

inline void cul2(ll s,ll t){
    if(NEXT[s][t]==t){RMQ[s][t]={0,1}; return;}
    RMQ[s][t]=RMQ[NEXT[s][t]][t];
    if(MX[NEXT[s][t]][0].S==s || MX[NEXT[s][t]][0].S==NEXT[NEXT[s][t]][t]){
        if(MX[NEXT[s][t]][1].S==s || MX[NEXT[s][t]][1].S==NEXT[NEXT[s][t]][t]){
            RMQ[s][t].F=max(RMQ[s][t].F,MX[NEXT[s][t]][2].F+RMQ[s][t].S);
        }
        else{
            RMQ[s][t].F=max(RMQ[s][t].F,MX[NEXT[s][t]][1].F+RMQ[s][t].S);
        }
    }
    else{
        RMQ[s][t].F=max(RMQ[s][t].F,MX[NEXT[s][t]][0].F+RMQ[s][t].S);
    }
    RMQ[s][t].S++;
    return;
}

inline void cul(ll s,ll t){
    pll &A1=MX[s][0].S==NEXT[s][t]?MX[s][1]:MX[s][0];
    pll &B1=(MX[t][0].S==NEXT[t][s]?MX[t][1]:MX[t][0]);
    pll &A2=(MX[s][0].S==NEXT[s][t] || MX[s][1].S==NEXT[s][t])?MX[s][2]:MX[s][1];
    pll &B2=(MX[t][0].S==NEXT[t][s] || MX[t][1].S==NEXT[t][s])?MX[t][2]:MX[t][1];
    {
        if(NEXT[s][t]==t){ans[s][t][3]=(A1.F>B1.F);}
        else if(A1.F>max(RMQ[s][t].F,B1.F)){ans[s][t][3]=true;}
        else if(MX[NEXT[s][t]][0].S==NEXT[NEXT[s][t]][t]){
            ans[s][t][3]=(MX[NEXT[s][t]][1].S==s?!ans[t][NEXT[s][t]][2]:!ans[t][NEXT[s][t]][3]);
        }
        else{
            ans[s][t][3]=(MX[NEXT[s][t]][0].S==s?!ans[t][NEXT[s][t]][2]:!ans[t][NEXT[s][t]][3]);
        }
    }
    {
        if(NEXT[s][t]==t){ans[s][t][2]=(A1.F>B2.F);}
        else if(A1.F>max(RMQ[s][t].F,B2.F)){ans[s][t][2]=true;}
        else if(MX[NEXT[s][t]][0].S==NEXT[NEXT[s][t]][t]){
            ans[s][t][2]=(MX[NEXT[s][t]][1].S==s?!ans[t][NEXT[s][t]][0]:!ans[t][NEXT[s][t]][1]);
        }
        else{
            ans[s][t][2]=(MX[NEXT[s][t]][0].S==s?!ans[t][NEXT[s][t]][0]:!ans[t][NEXT[s][t]][1]);
        }
    }
    {
        if(NEXT[s][t]==t){ans[s][t][1]=(A2.F>B1.F);}
        else if(A2.F>max(RMQ[s][t].F,B1.F)){ans[s][t][1]=true;}
        else if(MX[NEXT[s][t]][0].S==NEXT[NEXT[s][t]][t]){
            ans[s][t][1]=(MX[NEXT[s][t]][1].S==s?!ans[t][NEXT[s][t]][2]:!ans[t][NEXT[s][t]][3]);
        }
        else{
            ans[s][t][1]=(MX[NEXT[s][t]][0].S==s?!ans[t][NEXT[s][t]][2]:!ans[t][NEXT[s][t]][3]);
        }
    }
    {
        if(NEXT[s][t]==t){ans[s][t][0]=(A2.F>B2.F);}
        else if(A2.F>max(RMQ[s][t].F,B2.F)){ans[s][t][0]=true;}
        else if(MX[NEXT[s][t]][0].S==NEXT[NEXT[s][t]][t]){
            ans[s][t][0]=(MX[NEXT[s][t]][1].S==s?!ans[t][NEXT[s][t]][0]:!ans[t][NEXT[s][t]][1]);
        }
        else{
            ans[s][t][0]=(MX[NEXT[s][t]][0].S==s?!ans[t][NEXT[s][t]][0]:!ans[t][NEXT[s][t]][1]);
        }
    }
}

inline void merge(ll w,ll c){
    for(auto &I:children[c]){
        NEXT[w][I]=c;
        NEXT[I][w]=parent[I];
        cul2(w,I);
        cul2(I,w);
        cul(w,I);
        cul(I,w);
    }
    for(int i=1;i<children[w].size();i++){
        ll I=children[w][i];
        for(auto &T:children[c]){
            NEXT[I][T]=parent[I];
            NEXT[T][I]=parent[T];
            cul2(T,I);
            cul2(I,T);
            cul(T,I);
            cul(I,T);
        }
    }
    for(auto &I:children[c]){
        children[w].push_back(I);
    }
}

void dfs2(ll w,ll p,ll pn){
    if(MX[w][2].F<pn){MX[w][2]={pn,p};}
    if(MX[w][2]>MX[w][1]){swap(MX[w][1],MX[w][2]);}
    if(MX[w][1]>MX[w][0]){swap(MX[w][0],MX[w][1]);}
    children[w].push_back(w);
    for(auto &I:edge[w]){
        if(I==p){continue;}
        if(I==MX[w][0].S){
            dfs2(I,w,max(pn+1,MX[w][1].F+1));
        }
        else{
            dfs2(I,w,max(pn+1,MX[w][0].F+1));
        }
        merge(w,I);
    }
}



int main(){
    cin.tie(0);
    ios_base::sync_with_stdio(0);
    cin>>n;
    for(int i=1;i<n;i++){
        ll a,b;
        cin>>a>>b;
        a--; b--;
        edge[a].push_back(b);
        edge[b].push_back(a);
    }
    dfs1(0,-1);
    dfs2(0,-1,0);
    ll cnt=0;
    for(int i=0;i<n;i++){
        for(int t=0;t<n;t++){
            if(i==t){continue;}
            //if(ans[i][t][3]){cout<<i+1<<" "<<t+1<<endl;}
            if(ans[i][t][3]){cnt++;}
        }
    }
    cout<<cnt<<endl;
    
    
    return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 72928
final_rank: 1