- 给定一棵(n)个点的树,求用(l)条树上路经最多能覆盖多少个点。
- (nle10^6)
拓扑分层
显然路径的端点一定是叶节点(准确的说,由于这是无根树,应该是度数为(1)的节点),因为如果端点不是叶节点则路径必然可以继续拓展,答案不会变劣。
所以有了一个从叶节点向上逐层考虑的想法,但一个致命问题就在于叶节点的深度不一定相同,如果叶节点分散在很多层的话没法进行一个统一的处理。
这里就有一个非常奇妙的应对策略:我们不一定要让每个点的父节点与它在相邻层。
可以假定所有叶节点在同一层,然后跑一遍拓扑排序,定义一个点所在层数是它的所有子节点中最大的层数加(1)。
接着我们再回到最开始的想法,假设第(i)层点数为(cnt_i),显然第(i)层最多有(min{cnt_i,2l})个点被覆盖,而且每一层都能达到这个上界,这应该是很容易就能构造出来的。
代码:(O(n))
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000000
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
using namespace std;
int n,l,ee,lnk[N+5],deg[N+5];struct edge{int to,nxt;}e[2*N+5];
namespace FastIO
{
#define FS 100000
#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
char oc,FI[FS],*FA=FI,*FB=FI;
Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
}using namespace FastIO;
int q[N+5],rk[N+5],cnt[N+5];I void Topo()//拓扑排序
{
RI i,k,H=1,T=0;for(i=1;i<=n;++i) deg[i]==1&&(q[++T]=i);//从叶节点开始拓扑
W(H<=T) for(++cnt[rk[k=q[H++]]],i=lnk[k];i;i=e[i].nxt) --deg[e[i].to]==1&&(rk[q[++T]=e[i].to]=rk[k]+1);//子节点中最大层数+1
}
int main()
{
RI i,x,y;for(read(n),read(l),i=1;i^n;++i) read(x),read(y),add(x,y),add(y,x),++deg[x],++deg[y];
RI t=0;for(Topo(),i=0;i<=n;++i) t+=min(cnt[i],l<<1);return printf("%d
",t),0;//第i层选择min{cnt[i],2l}个点
}