hdu4607 (求树的直径)

题意:给你一颗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+最长权值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值