■ ポイント1
|n1以下の集合 ∩ n2以下の集合| = Xect[n1][n2] |n1以下の集合以外 ∩ n2以下の集合| = size[Tree2][n2] - Xect[n1][n2] |n1以下の集合 ∩ n2以下の集合以外| = size[Tree1][n1] - Xect[n1][n2] |n1以下の集合以外 ∩ n2以下の集合以外| = (N - size[Tree1][n1]) - (size[Tree2][n2] - Xect[n1][n2]) n1以下以外 n2以下以外 0 1 2 2 3 n1以下 n2以下 3 4 0 1 4 のとき Xect[n1][n2] = |{4}| = 1 n1以下以外 ∩ n2以下 は? → 0 1 4 のうち 4 は Xect に入ってるので n1 以下にあるので "n1以下以外 ∩ n2以下" には含まれない。 → それ以外の 0 1 は n1 以下にはないはずなので n1 以下以外にあるはず→つまり n1以下以外 ∩ n2以下 に含まれる なので size[Tree2][n2] - Xect[n1][n2]
■ ポイント2
// 理解した後に書いたコード (ほぼそのままですね class TreesAnalysis { public: void dfs(int t, int idx, int prev, vector<VVI>& g, VVI& size, VVI& xect) { int N = xect.size(); size[t][idx]=1; REP(i, g[t][idx].size()) { int ci=g[t][idx][i]; if(ci==prev) continue; dfs(t, ci, idx, g, size, xect); size[t][idx]+=size[t][ci]; REP(j, N) xect[idx][j]+=xect[ci][j]; } } long long treeSimilarity(vector <int> T1, vector <int> T2) { int N=T1.size()+1; vector<VVI> g(2, VVI(N)); VVI size(2, VI(N)); VVI xect(N, VI(N)); REP(t, 2) REP(i, N-1) { int j=(t==0?T1:T2)[i]; g[t][i].PB(j); g[t][j].PB(i); } REP(i, N) xect[i][i]=1; REP(t, 2) { dfs(t, 0, -1, g, size, xect); REP(i, N) RANGE(j, i+1, N) swap(xect[i][j], xect[j][i]); } ll ans = 0; RANGE(i, 1, N) RANGE(j, 1, N) { int x=xect[i][j]; int a=size[0][i]; int b=size[1][j]; ll add = max(x, max(a-x, max(b-x, N-a-(b-x)))); ans += add*add; } return ans; } };