树的直径相关吧。
首先k=1时,非常简单只需要在直径的两端连一条边。
当k=2时,先在直径的两端连一条边,之后把直径上每条边边权变为-1,再求一遍直径,为什么呢?
边权变成-1,等价于多走两遍。
注意第二次不能用两次bfs,因为有负数边。
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #define maxn 100010 using namespace std; int f1[maxn],f2[maxn],s1[maxn],s2[maxn],pre[maxn]; int next[2*maxn],to[2*maxn],head[maxn],len[2*maxn],fr[2*maxn]; int n,m,num,k,root; void addedge(int x,int y) { num++;to[num]=y;fr[num]=x;len[num]=1;next[num]=head[x];head[x]=num; } void dfs(int x,int fa) { s1[x]=s2[x]=x; for (int p=head[x];p;p=next[p]) if (to[p]!=fa) { pre[to[p]]=p; dfs(to[p],x); if (f1[to[p]]+len[p]>f1[x]) { f2[x]=f1[x]; s2[x]=s1[x]; f1[x]=f1[to[p]]+len[p]; s1[x]=s1[to[p]]; } else if (f1[to[p]]+len[p]>f2[x]) { f2[x]=f1[to[p]]+len[p]; s2[x]=s1[to[p]]; } } if (f1[x]+f2[x]>f1[root]+f2[root]) root=x; } int main() { scanf("%d%d",&n,&k); num=1; for (int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); addedge(x,y);addedge(y,x); } dfs(1,0); int ans=2*(n-1)-f1[root]-f2[root]+1; if (k==1) printf("%d\n",ans); else { int x=s1[root]; while (x!=root) len[pre[x]]=-1,len[pre[x]^1]=-1,x=fr[pre[x]]; x=s2[root]; while (x!=root) len[pre[x]]=-1,len[pre[x]^1]=-1,x=fr[pre[x]]; memset(f1,0,sizeof(f1)); memset(f2,0,sizeof(f2)); dfs(1,0); ans=ans-f1[root]-f2[root]+1; printf("%d\n",ans); } return 0; }