题意:给你一颗n个节点的无根树,m次询问,问经过k个点的最少路程,树上每条边默认权值为1.
思路:先求出树上最长路的长度ans,然后思考一下找规律发现,满足k<=ans, 结果就是 k-1,否则结果就是(k-ans)*2+ans-1。
#include<bits/stdc++.h>
using namespace std;
template<int N,int M>//N点的个数,M边的个数
struct Graph
{
int top;
struct Vertex{
int head;
}V[N];
struct Edge{
int v,next;
}E[M];
void init(){
memset(V,-1,sizeof(V));
top = 0;
}
void add_edge(int u,int v){
E[top].v = v;
E[top].next = V[u].head;
V[u].head = top++;
}
};
const int N=100000+10;
Graph<N,N*2> g;
int n,m,dp[N][2],ans;
void dfs(int u,int f){
for(int i=g.V[u].head;i!=-1;i=g.E[i].next){
int v=g.E[i].v;
if(v==f) continue;
dfs(v,u);
if(dp[v][0]+1>=dp[u][0]){
dp[u][1]=dp[u][0];
dp[u][0]=dp[v][0]+1;
}
else if(dp[v][0]+1>dp[u][1]) dp[u][1]=dp[v][0]+1;
}
ans=max(ans,dp[u][0]+dp[u][1]);
}
int main(){
int T;scanf("%d",&T);
while(T--){
g.init();memset(dp,0,sizeof(dp));
scanf("%d%d",&n,&m);
for(int i=0;i<n-1;i++){
int a,b;scanf("%d%d",&a,&b);
g.add_edge(a,b);
g.add_edge(b,a);
}
ans=0;
dfs(1,-1); ans++;
while(m--){
int x;scanf("%d",&x);
if(x<=ans) printf("%d\n",x-1);
else printf("%d\n",2*x-ans-1);
}
}
}
后话:如果这里树上每边都有权值,而不是默认长度为1,解法还是这个吗? 我想了一下 还是这个… 你先求出整个树的边权值之和,和权值最大的那条边权值和,结果也是(总和-最长之和)*2+最长权值。