题意: 一个
很明显,树上
如果
如果
这时如果
需要注意的是,由于第一次找直径完后需要改变边权,所以需要记录边,故第一次最好使用搜索找直径,而第二次由于边权改为了
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
int n,k;
int f[101010],d[101010];
int dis[101010],vis[101010];
int ans,rt;
int head[201010],cnt;
struct node
{
int next;
int to;
int num;
}e[201010];
void add(int from,int to,int num)
{
e[++cnt].next=head[from];
e[cnt].to=to;
e[cnt].num=num;
head[from]=cnt;
}
void dfs(int u)
{
vis[u]=1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(vis[v])
continue;
d[v]=i;//注意,d数组存储路径存储的是编号,这样即可方便找到边。
dis[v]=dis[u]+e[i].num;
if(dis[v]>ans)
{
ans=dis[v];
rt=v;
}
dfs(v);
}
return ;
}
void dp(int u,int fa)
{
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa)
continue;
dp(v,u);
ans=max(ans,f[u]+f[v]+e[i].num);
f[u]=max(f[u],f[v]+e[i].num);
}
}
int main()
{
scanf("%d%d",&n,&k);
cnt=1;
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b,1);
add(b,a,1);
}
if(k==1)
{
dp(1,0);
printf("%d",2*n-ans-1);
return 0;
}
else
{
dfs(1);
int p=rt;
ans=0;
rt=0;
memset(dis,0,sizeof(dis));
memset(d,0,sizeof(d));
memset(vis,0,sizeof(vis));
dfs(p);
int l1=ans;
for(;d[rt];rt=e[d[rt]^1].to)//直接用边,找到对应边的反边的to,即上一个
e[d[rt]].num=e[d[rt]^1].num=-1;
ans=0;
dp(1,0);
int l2=ans;
printf("%d",2*n-l1-l2);
return 0;
}
return 0;
}