\(O(n^2)\) 的作法就是每次 dfs 整棵樹 貪心從下往上選,具體而言就是維護以 u 兒子傳上來的最長鏈和次長鏈,若是最長鏈 + 次長鏈 + 1 \(\geq\) \(k\) 則拼成一條長度爲 \(k\) 的鏈,而後穿一條長度爲 0 的上去,不然把最長鏈傳上去。ios
正確性:因爲當前存在最長鏈 + 次長鏈 +1\(\geq\) \(k\),就算傳一條最長鏈上去也只可能使答案增長1,而不如如今就讓最長鏈匹配了次長鏈產生1的貢獻,可能會更優。git
發現當\(k\geq \sqrt n\)時,答案 \(\le \sqrt n\),並且不難發現答案隨着k變大變小,而且由一些連續段拼接而成,咱們對於每一個答案二分其最右邊的端點使得這一塊的答案同樣,因此總時間複雜度爲 \(O(n\sqrt n\log n)\)。spa
這題比較卡常,不能寫遞歸的 dfs,把每一個點的 dfn 序搞出來就能夠用 for 循環實現了。code
#include <iostream> #include <cmath> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <fstream> using namespace std; #define LL long long #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define MP(x, y) std::make_pair(x, y) #define DEBUG(...) fprintf(stderr, __VA_ARGS__) #define REP(i, a, b) for (register int (i) = (a); (i) <= (b); ++(i)) #define GO cerr << "GO" << endl; inline void proc_status() { ifstream t("/proc/self/status"); cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl; } template<class T> inline T read() { register char c; register T x(0), f(1); while (!isdigit(c = getchar())) if (c == '-') f = -1; while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar())); return x * f; } template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; } template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; } const int maxN = (int) 1e5; int n; int ans[maxN + 2],ver[maxN<<1],nxt[maxN<<1],head[maxN+2],tot,dfst,rev[maxN+2]; int first[maxN+2],second[maxN+2],fa[maxN+2]; void link(int u, int v) { ver[++tot]=v,nxt[tot]=head[u],head[u]=tot; } void Input() { n = read<int>(); for (int i = 1; i < n; ++i) { int u = read<int>(), v = read<int>(); link(u, v), link(v, u); } } void dfs(int u, int f) { rev[++dfst]=u; fa[u]=f; for (int i = head[u];i;i=nxt[i]) { int v=ver[i]; if(v==f)continue; dfs(v,u); } } inline int Calc(int l) { memset(first,0,4*(n+1)); memset(second,0,4*(n+1)); int res(0); for (register int i = n; i >= 1; --i) { int u=rev[i],f=fa[u],len; if(first[u]+second[u]+1>=l) ++res,len=0; else len=first[u]+1; if (!f) continue; if(first[f] < len)second[f]=first[f],first[f]=len; else if(second[f]<len)second[f]=len; } return res; } void Solve() { int i; int sqr = int(sqrt(n)); dfs(1,0); for (i = 1; i <= sqr; ++i) ans[i] = Calc(i); for (; i <= n; ++i) { ans[i]=Calc(i); int l=i,r=n,pos=i,mid; while (l<=r) { mid=(l+r)>>1; if(Calc(mid)==ans[i])pos=mid,l=mid+1; else r=mid-1; } for(int j=i+1;j<=pos;++j)ans[j]=ans[i]; i=pos; } for(int i=1;i<=n;++i) printf("%d\n",ans[i]); } int main() { Input(); Solve(); return 0; }