Subject
Given a tree with \ (n \) nodes, for each number between \ (1 \) ~ \ (n \) \ (k \) , you need to ask: how many items can be selected at most The length of each intersecting path is \ (k \) .
\(Solution:\)
\ (1 \) ~ \ (n \) is not easy to count, first consider a single \ (k \) .
Let \ (ans_i \) indicate the maximum number of mutually disjoint paths that can be selected. The length of each path is \ (i \) . \ (F_u \) indicates that the maximum number of paths can be selected when backtracking to \ (u \) How many paths do not intersect each other, the length of each path is \ (i \) ( \ (i \) is the previous \ (i \) );
Consider greedy \ (DP \) : For a point \ (U \) , we consider to maximize the \ (U \) is the subtree rooted at the full length of \ (K \) path number of , secondly largest The length of the unfinished chain ; the
correctness is obviously: due to the nature of the tree, the \ (u \) node will only be counted in one path, then we use a similar point of view to divide and conquer, let \ (u \) be the \ (Dep \) is the shallowest point on the path , \ (max1 \) is the length of the longest chain hanging down from the \ (u \) node, \ (max2 \) is \ (u \) hanging down The length of the second longest chain, then:
\ ((1) \) If \ (max1 + max2 + 1 \ geq k \) , then we obviously want to include the path composed of \ (max1, max2, u \) into the answer , Otherwise the ancestor node of \ (u \) will be used , which is not optimal;
\ ((2) Otherwise \) , we will use the chain of \ (max1, u \) to inherit
Code probably look like this (read \ (lzy \) Gangster \ (Blog \) , discovered that in fact you can first \ (dfs \) again ran \ (dfs \) sequence, and then directly in the \ (dfs \) Operate in sequence, new skills \ (get \) )
void dfs(int u,int fa)
{
fat[u]=fa;
go(u)
{
int v=e[i].to;
if(v!=fa) dfs(v,u);
}
dfn[++idx]=u;
}
inline int solve(int k)
{
int ans=0;
fr(i,1,n) f[i]=1;
fr(i,1,n)
{
int u=dfn[i];
if(fat[u]&&f[fat[u]]&&f[u])
{
if(f[u]+f[fat[u]]>=k)
{
++ans,f[fat[u]]=0;
}
else f[fat[u]]=max(f[fat[u]],f[u]+1);
}
}
return ans;
}
However, this is \ (O (n ^ 2) \) , consider optimization. It can be found that: \ (ans_i \ leq \ frac {n} {i} \) (the reason is that the path length is \ (i \) , then the best case is to use all the points, there will be \ (\ frac { n} {i} \) paths).
Then combined with the data range \ (n \ leq 10 ^ 5 \) , we can divide and conquer with the root sign: for a certain \ (k \) , we set a threshold \ (B \) :
\ ((1) \) If \ (k \ leq B \) , direct violence \ (dp \) (that is, the above code), complexity \ (O (nB) \) ;
\ ((2) \) If \ (k> B \) , there must be: \ (ans_k \ in [0, \ frac {n} {B}] \) , that is, only \ (\ frac {n} {B} \) has so many values , Then \ (f \) (that is, \ (dp \) array) obviously has a monotonous and non-increasing nature, that is to say , the dp value of a segment in the middle is the same , then we consider dichotomizing the boundaries of these segments, each time used solve()
to \ (Check \) , the complexity of the \ (O (\ {n-FRAC} {B} n-\ n-log_2) \) .
Then we now analyze the value of the threshold \ (B \) . From the above analysis, we can see that the total complexity \ (O (nB + \ frac {n} {B} n \ log_2 n) = O (n (B + \ frac {n} {B} \ log n)) \) , by the mean inequality: \ (min = n \ sqrt {n \ log n} \) , if and only \ (B = \ frac {n} {B} \ log n \) is obtained when \ (B = \ sqrt {n \ log n} \) .
Code above:
\(Code:\)
#include<bits/stdc++.h>
using namespace std;
namespace my_std
{
typedef long long ll;
typedef double db;
#define pf printf
#define pc putchar
#define fr(i,x,y) for(register int i=(x);i<=(y);++i)
#define pfr(i,x,y) for(register int i=(x);i>=(y);--i)
#define go(x) for(int i=head[u];i;i=e[i].nxt)
#define enter pc('\n')
#define space pc(' ')
#define fir first
#define sec second
#define MP make_pair
const int inf=0x3f3f3f3f;
const ll inff=1e15;
inline int read()
{
int sum=0,f=1;
char ch=0;
while(!isdigit(ch))
{
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch))
{
sum=sum*10+(ch^48);
ch=getchar();
}
return sum*f;
}
inline void write(int x)
{
if(x<0)
{
x=-x;
pc('-');
}
if(x>9) write(x/10);
pc(x%10+'0');
}
inline void writeln(int x)
{
write(x);
enter;
}
inline void writesp(int x)
{
write(x);
space;
}
}
using namespace my_std;
const int N=1e5+50;
int n,B,idx,f[N],fat[N],dfn[N],head[N],cnt,ans[N];
struct edge
{
int to,nxt;
}e[N<<1];
inline void add(int u,int v)
{
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
void dfs(int u,int fa)
{
fat[u]=fa;
go(u)
{
int v=e[i].to;
if(v!=fa) dfs(v,u);
}
dfn[++idx]=u;
}
inline int solve(int k)
{
int ans=0;
fr(i,1,n) f[i]=1;
fr(i,1,n)
{
int u=dfn[i];
if(fat[u]&&f[fat[u]]&&f[u])
{
if(f[u]+f[fat[u]]>=k)
{
++ans,f[fat[u]]=0;
}
else f[fat[u]]=max(f[fat[u]],f[u]+1);
}
}
return ans;
}
int main(void)
{
n=read();
B=sqrt(n*log(n)/log(2));
fr(i,1,n-1)
{
int u=read(),v=read();
add(u,v),add(v,u);
}
dfs(1,0);
//fr(i,1,n) writesp(dfn[i]);
ans[1]=n;
fr(i,2,B) ans[i]=solve(i);
for(int i=B+1,l,r;i<=n;i=l+1)
{
l=i,r=n;
int tmp=solve(i);
while(r-l>1)
{
int mid=(l+r)>>1;
if(solve(mid)==tmp) l=mid;
else r=mid;
}
fr(j,i,l) ans[j]=tmp;
}
fr(i,1,n) writeln(ans[i]);
return 0;
}