传送门
题意:
有一颗nnn个节点的树,其中一个简单路径集合被称为kkk合法当且仅当:
树的每个节点至多属于一条路径,且每条路径恰好包含kkk个点。
对于k∈[1,n]k\in [1,n]k∈[1,n],求kkk合法路径集合最多路径个数,即设kkk合法路径集合为SSS,求最大的∣S∣|S|∣S∣。
2≤n≤1e52\le n\le 1e52≤n≤1e5
思路:
考虑每次用dpdpdp来O(n)O(n)O(n)来求,记一个最大值和次大值,让后就是比较常规的dpdpdp了,这样的复杂度是O(n2)O(n^2)O(n2)的。
考虑到当k∈[n,n]k\in [\sqrt n,n]k∈[n,n]的时候,答案不会超过n\sqrt nn个,也就是每个答案有可能很长一段连续的都是这个答案,且答案递减,所以这个东西有二分的性质。
考虑根号分治,对于k∈[1,n]k\in [1,\sqrt n]k∈[1,n]的情况,我们直接暴力求,复杂度O(nn)O(n\sqrt n)O(nn)。对于k∈[n,n]k\in [\sqrt n,n]k∈[n,n],我们每次二分答案所属区间,复杂度O(nnlogn)O(n\sqrt n logn)O(nnlogn)。
直接写会ttt掉,毕竟这个复杂度还是很高的,所以考虑将dpdpdp的dfsdfsdfs拿出来dfsdfsdfs序,循环跑一下,这样会快很多,可以通过。
// Problem: D. You Are Given a Tree
// Contest: Codeforces - Codeforces Round #507 (Div. 1, based on Olympiad of Metropolises)
// URL: https://codeforces.com/problemset/problem/1039/D
// Memory Limit: 512 MB
// Time Limit: 7000 ms
//
// Powered by CP Editor (https://cpeditor.org)//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;const int N=100010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;int n;
int ans[N],block;
vector<int>v[N];
int dfn[N],tot,fa[N],id[N];void dfs(int u,int f) {int mx1=0,mx2=0;int now=0;fa[u]=f;dfn[u]=++tot;for(auto x:v[u]) {if(x==f) continue;dfs(x,u);// now+=y;// if(mx1<len[x]) mx2=mx1,mx1=len[x];// else if(mx2<len[x]) mx2=len[x];}// if(mx1+mx2+1>=k) now++,len[u]=0;// else len[u]=mx1+1;// return now;
}int f[N],mx1[N],mx2[N];
int len[N];int solve(int k) {if(ans[k]!=-1) return ans[k];for(int i=0;i<=n;i++) {mx1[i]=mx2[i]=0;f[i]=0;len[i]=0;}for(int i=1;i<=n;i++) {int now=id[i];int to=fa[now];if(mx1[now]+mx2[now]+1>=k) {f[now]++; len[now]=0;} else len[now]=mx1[now]+1;f[to]+=f[now];if(mx1[to]<len[now]) {mx2[to]=mx1[to];mx1[to]=len[now];} else if(mx2[to]<len[now]) {mx2[to]=len[now];}}return ans[0]=f[0];
}bool cmp(int a,int b) {return dfn[a]>dfn[b];
} int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);memset(ans,-1,sizeof(ans));scanf("%d",&n); block=sqrt(n*log(n)/log(2));for(int i=1;i<=n-1;i++) {int a,b; scanf("%d%d",&a,&b);v[a].pb(b); v[b].pb(a);}dfs(1,0);for(int i=1;i<=n;i++) ans[i]=-1,id[i]=i;sort(id+1,id+1+n,cmp);for(int i=1;i<=block;i++) {ans[i]=solve(i);}int pre=block+1;for(int _=1;pre<=n;_++) {int l=pre,r=n,ne,val;val=solve(l);while(l<=r) {int mid=(l+r)>>1;if(solve(mid)<val) r=mid-1;else l=mid+1,ne=mid;}for(int i=pre;i<=ne;i++) ans[i]=solve(pre);pre=ne+1; }for(int i=1;i<=n;i++) printf("%d\n",ans[i]);return 0;
}
/**/