\(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; }