题目链接:http://codeforces.com/problemset/problem/958/B2
题意:
你现在有一棵n个点的树,有若干个地标,你可以把这些地标放在树的结点上,被地标占的结点和每两个地标之间的简单路径上的结点都标红,现在问你,假设你有1,2,3....,n个地标时,最多有多少结点可以被染红。
做法:
很明显你会发现,一定是叶子结点被占用的时候才会染最多的地标,假设叶子结点的数量为x,当你有x个地标时也就做完了,现在的问题时,当你把叶子结点放上的时候,会有一串的结点都可以被忽略,你也会发现,两个地标时能染红的数量就是树的直径。
你会发现,假设我们从树直径上的一个点走,每遇到一个分叉,都会增加一个新的叶子,而每个叶子又可以当做是一个新的数,新的数上找深度最大的儿子结点,就是这个树假设没有分叉的贡献。
那么我们就可以用dp来做,dp[i]表示以结点i为根,它的最长儿子链+1(它自己),除最长儿子链以外的结点的dp,就又是一个新的可加值,所有的可加值从大到小取,就是我们要的顺序。
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,dp[maxn],more[maxn],now,cnt,ans[maxn];
struct edge{
int v,next;
}e[maxn<<1];
int head[maxn],rt,dep[maxn],son[maxn];
void add(int u,int v){
e[cnt].v=v, e[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int u,int fa){
for(int i=head[u];~i;i=e[i].next){
int v=e[i].v;
if(v==fa) continue;
dep[v]=dep[u]+1;
dfs(v,u);
}
if(dep[u]>dep[rt]) rt=u;
}
void Dpdfs(int u,int fa){
for(int i=head[u];~i;i=e[i].next){
int v=e[i].v;
if(v==fa) continue;
Dpdfs(v,u);
if(dp[v]>dp[son[u]]) son[u]=v;
}
dp[u]=dp[son[u]]+1;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].v;
if(v!=fa&&v!=son[u]){
more[++now]=dp[v];
}
}
}
bool cmp(int a,int b){return a>b;}
int main(){
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
dfs(1,0);
Dpdfs(rt,-1);
more[++now]=dp[rt];
sort(more+1,more+1+now,cmp);
for(int i=1;i<=now;i++){
ans[i+1]=ans[i]+more[i];
}
ans[1]=1;
for(int i=now+1;i<=n;i++) ans[i]=n;
for(int i=1;i<=n;i++){
printf("%d%c",ans[i],i==n?'\n':' ');
}
return 0;
}