hdu - 4607 - Park Visit

题意:N个城市形成一棵树,相邻城市之间的距离是1,问游K个城市的最短路程是多少,共有M次询问(1 <= N, M <= 100000, 1 <= K <= N)。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4607

——>>把这棵树拉直,得最长路(直径)共有maxd个城市,如果K <= maxd,只要一直向前走,路程为K - 1;如果K > maxd,贪心策略为最长路一定要从头走到尾,中间补上缺少的城市,每补一个,距离+2,结果是maxd - 1 + (K - maxd) * 2。

对于最长路(直径),可用无根树转有根树,第一次任选一点作根转一次,然后找出最深的叶子,第二次以这个最深的叶子为根转一次,树的层数就是最长路的长度。

#include <cstdio>
#include <vector>

using namespace std;

const int maxn = 100000 + 10;
vector<int> G[maxn];
int d[maxn];

void dfs(int u, int fa, int cur)        //现在的点为u,其父结点为fa,从根到u的经过cur个点
{
    d[u] = cur;
    int cnt = G[u].size();
    for(int i = 0; i < cnt; i++)
    {
        int v = G[u][i];
        if(v != fa) dfs(v, u, cur+1);
    }
}

int main()
{
    int T, N, M, u, v, i, j, K;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &N, &M);
        for(i = 1; i <= N; i++) G[i].clear();
        for(i = 0; i < N-1; i++)
        {
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1, 0, 1);       //第一次转有根树,找一个最长路的一端
        j = 1;
        for(i = 2; i <= N; i++) if(d[i] > d[j]) j = i;
        dfs(j, 0, 1);       //第二次转有根树,找最长路
        j = 1;
        for(i = 2; i <= N; i++) if(d[i] > d[j]) j = i;
        int maxd = d[j], ret;
        for(i = 0; i < M; i++)
        {
            scanf("%d", &K);
            if(K <= maxd) ret = K - 1;
            else ret = maxd - 1 + (K - maxd) * 2;
            printf("%d\n", ret);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值