/* * Disclaimer: All code enclosed within “namespace zawa” is available at the following link. * https://zawa-tin.github.io/cp-documentation/ */ #include #include #include #include #include #include #include #include #include #include // #include "Src/Number/IntegerDivision.hpp" // #include "Src/Utility/BinarySearch.hpp" // #include "Src/Sequence/CompressedSequence.hpp" // #include "Src/Sequence/RunLengthEncoding.hpp" // #include "Src/Algebra/Group/AdditiveGroup.hpp" // #include "Src/DataStructure/FenwickTree/FenwickTree.hpp" // #include "Src/DataStructure/SegmentTree/SegmentTree.hpp" // #include "Src/DataStructure/DisjointSetUnion/DisjointSetUnion.hpp" // #include "Src/DataStructure/Heap/BinaryHeap.hpp" #include #include namespace zawa { using i16 = std::int16_t; using i32 = std::int32_t; using i64 = std::int64_t; using i128 = __int128_t; using u8 = std::uint8_t; using u16 = std::uint16_t; using u32 = std::uint32_t; using u64 = std::uint64_t; using usize = std::size_t; } // namespace zawa #include namespace zawa { namespace concepts { template concept TreeDP = requires { typename T::Tree; typename T::Cluster; typename T::Edge; typename T::Vertex; { T::Convert(std::declval()) } -> std::same_as; { T::AddEdge(std::declval(), std::declval()) } -> std::same_as; { T::Merge(std::declval(), std::declval()) } -> std::same_as; { T::AddVertex(std::declval(), std::declval()) } -> std::same_as; }; } template class Rerooting { public: using Tree = DP::Tree; using Cluster = DP::Cluster; using Edge = DP::Edge; using Vertex = DP::Vertex; Rerooting(usize n,std::vector> ed,std::vector vs,std::vector es) : m_n{n}, m_edges{std::move(ed)}, m_alls(n), m_sides(m_edges.size()) { assert(m_edges.size()+1==n); assert(m_edges.size()==es.size()); assert(n==vs.size()); if (n==1) { m_alls[0]=DP::Convert(vs[0]); return; } std::vector>> g(n); for (usize i = 0 ; auto [u,v] : m_edges) { g[u].push_back({v,i}); g[v].push_back({u,i}); i++; } std::vector dp(n); auto dfs1=[&](auto dfs,T v,T p) -> Tree { if (std::ssize(g[v])==1 and g[v][0].first==p) return dp[v]=DP::Convert(vs[v]); usize idx=g[v][0].first==p?1:0; assignToSides(dfs(dfs,g[v][idx].first,v),g[v][idx].second,g[v][idx].first); Cluster prod=DP::AddEdge(dp[g[v][idx].first],es[g[v][idx].second]); for (idx++ ; idx(0)); auto dfs2=[&](auto dfs,T v,T p,Tree t) -> void { const usize k=g[v].size(); std::vector clusters(k); for (usize i = 0 ; i < k ; i++) { if (g[v][i].first==p) { assignToSides(t,g[v][i].second,p); clusters[i]=DP::AddEdge(t,es[g[v][i].second]); } else clusters[i]=DP::AddEdge(dp[g[v][i].first],es[g[v][i].second]); } if (k==1) { m_alls[v]=DP::AddVertex(clusters[0],vs[v]); if (g[v][0].first!=p) { assert(!v); dfs(dfs,g[v][0].first,v,DP::Convert(vs[v])); } } else { std::vector pref=clusters,suf=clusters; for (usize i = 1 ; i < k ; i++) { pref[i]=DP::Merge(pref[i-1],clusters[i]); suf[k-i-1]=DP::Merge(clusters[k-i-1],suf[k-i]); } m_alls[v]=DP::AddVertex(pref[k-1],vs[v]); for (usize i = 0 ; i < g[v].size() ; i++) if (g[v][i].first!=p) { Cluster pc=i?(i+1(0),Tree{}); } inline usize size() const noexcept { return m_n; } const Tree& operator[](usize i) const noexcept { assert(i < size()); return m_alls[i]; } const Tree& side(usize i,T v) const { assert(i < m_sides.size()); if (m_edges[i].first==v) return m_sides[i].first; else if (m_edges[i].second==v) return m_sides[i].second; assert(0); return m_sides[i].first; } private: void assignToSides(Tree t,usize idx,T v) { if (m_edges[idx].first==v) m_sides[idx].first=std::move(t); else m_sides[idx].second=std::move(t); } usize m_n; std::vector> m_edges; std::vector m_alls; std::vector> m_sides; }; } // namespace zawa namespace zawa {} using namespace zawa; // #include "atcoder/modint" // using mint = atcoder::modint998244353; // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #pragma GCC target("avx2") // #pragma GCC optimize("O3") // #pragma GCC optimize("unroll-loops") using namespace std; template ostream& operator<<(ostream& os, const pair& p) { os << '(' << p.first << ',' << p.second << ')'; return os; } template ostream& operator<<(ostream& os, const vector& v) { for (int i = 0 ; i < ssize(v) ; i++) os << v[i] << (i + 1 == ssize(v) ? "" : " "); return os; } /* * */ struct DP { using Tree = int; using Cluster = int; using Edge = struct {}; using Vertex = struct {}; static Tree Convert(Vertex) { return 1; } static Cluster AddEdge(Tree t,Edge) { return t+1; } static Cluster Merge(Cluster l,Cluster r) { return max(l,r); } static Tree AddVertex(Cluster c,Vertex) { return c; } }; int main() { cin.tie(0); cout.tie(0); ios::sync_with_stdio(0); cout << fixed << setprecision(20); #if !defined DEBUG int N; cin >> N; vector> E(N-1); vector>> G(N); for (int i = 0 ; auto& [u,v] : E) { cin >> u >> v; u--; v--; G[u].push_back({v,i}); G[v].push_back({u,i}); i++; } Rerooting dp(N,E,vector(N),vector(N-1)); int ans=0; for (int v = 0 ; v < N ; v++) { vector paths; for (auto [x,i] : G[v]) paths.push_back(dp.side(i,x)); ranges::sort(paths); int cnt=ssize(paths); for (int j : paths) { ans=max(ans,j*cnt+1); cnt--; } } cout << ans << '\n'; #else mt19937_64 mt{random_device{}()}; for (int testcase = 0 ; ; ) { cerr << "----------" << ++testcase << "----------" << endl; auto a = solve(), b = naive(); if (a != b) { // print testcase cerr << "you: " << a << endl; cout << "correct: " << b << endl; exit(0); } } #endif }