题目
传送门:QWQ
分析
$ k=1 $ 时显然就是树的直径
$ k=2 $ 时怎么做呢?
做法是把一开始树的直径上的边的边权改成$ -1 $,那么当我们第二次用这些边做环时就抵消了一开始的贡献。
所以答案就是边的数量*2 - 一开始树的直径 - 后来树的直径
P.S. 第二次求树的直径时只能dp
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=;
int n,dis[maxn], inq[maxn] ;
struct Edge{ int u,v,dis; };
vector<int> G[maxn]; vector<Edge> edges;
queue<int> que;
void addedge(int a,int b,int c){
edges.push_back((Edge){a,b,c}); edges.push_back((Edge){b,a,c});
int m=edges.size(); G[a].push_back(m-); G[b].push_back(m-);
}
int spfa(int s){
memset(dis,-,sizeof(dis));
memset(inq,,sizeof(inq));
dis[s]=;
que.push(s); inq[s]=;
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=;i<G[u].size();i++){
int v=edges[G[u][i]].v;
if(!inq[v] && dis[v]<dis[u]+edges[G[u][i]].dis){
dis[v]=dis[u]+edges[G[u][i]].dis;
if(!inq[v]){que.push(v); inq[v]=; }
}
}
}
int q=,ans,maxnum=-;
for(int i=;i<=n;i++) if(i!=s && dis[i]==dis[s]) q=;
for(int i=;i<=n;i++){
if(dis[i]>maxnum && (q||i!=s)){ maxnum=dis[i]; ans=i; }
}
return ans;
}
void dfs(int p,int fa){
if(dis[p]==) return;
for(int i=;i<G[p].size();i++){
int v=edges[G[p][i]].v;
if(v!=fa && dis[v]==dis[p]-){
edges[G[p][i]].dis=-; edges[G[p][i]^].dis=-; dfs(v,p);
}
}
}
int ansa=;
int dp(int x,int fa){
int big1=,big2=;
for(int i=;i<G[x].size();i++){
int v=edges[G[x][i]].v; if(v==fa) continue;
int k=dp(v,x)+edges[G[x][i]].dis;
if(big1<k){big2=big1; big1=k;}
else if(big2<k){ big2=k; }
}
if(big1+big2 > ansa) ansa=big1+big2;
return big1;
}
int main(){
int a,b,k;
scanf("%d%d",&n,&k);
for(int i=;i<n;i++){
scanf("%d%d",&a,&b);
addedge(a,b,);
}
int p=spfa();
int q=spfa(p);
int ans =*n--dis[q];
if(k==){
dfs(q,); dp(,);
ans-=ansa-;
}
printf("%d\n",ans);
return ;
}