2022-05-05每日刷题打卡

2022-05-05每日刷题打卡

代码源——每日一题

Collision - 题目 - Daimayuan Online Judge
题目描述

siyisss 的王国是由 n 个村镇和 n−1 条双向道路构成的,村镇从 1 到 n 依次编号,每条双向道路连接两个不同的村镇,使得从任意一个村镇出发都可以到达任意一个村镇。接下来请你回答 q 个问题,每次给出两个整数 c, d,表示现在分别有一个人在村镇 c,一个人在村镇 d,现在在 c 的人要用最短的时间到达村镇d,在村镇 d 的人要以最短的时间到达村镇 c,假设两人同时出发,两人的速度也是一样的,每条双向道路的长度也是一样的,请问两人相遇的时候是在某一个村镇,还是在某条双向道路上?

输入描述

第一行输入两个整数 n, q 代表村镇的数量和询问的数量

接下来 n−1 行,每行两个整数用来描述一条双向道路

最后 q,每行两个整数代表 c, d

输出描述

对于每个询问,如果他们在某个村镇相遇,请示出Town,否则输出Road

样例输入1
9 9
2 3
5 6
4 8
8 9
4 5
3 4
1 9
3 7
7 9
2 5
2 6
4 6
2 4
5 8
7 8
3 6
5 6
样例输处1
Town
Road
Town
Town
Town
Town
Road
Road
Road
数据范围

2≤n≤100000

1≤q≤100000

对于每一个询问 1≤ci<di≤n

问题解析

先说结论:当两个点的距离为奇数时,俩人会在路上遇到;当距离为偶数时,俩人会在镇子上遇到。因为俩人同时间走过的长度一样,当两点距离为奇数时,俩人最后会在中间的路上遇到;偶数就会在中间的镇子遇到,很简单的道理。

暴力做法是:我们可以先建图,然后每次询问跑一次bfs,看这个点到另一个点的最短路距离是多少,再根据这个距离的奇偶性来输出结果。但是要是每次都跑一趟肯定会t,能不能优化一下?

(今天比较懒就不一步步来了,直接说终极版本(对我来说是,因为我不会dij等求最短路的,所以我做法很朴实))

为了方便理解做成树的样子(其实和图一样,只是为了方便理解这么画):
在这里插入图片描述

然后我们就跑一趟bfs,求出每个点到根节点1的最短距离,把这些存入数组dist里:dist[i]是点i到1的距离。然后我们可以这么看,如果一个点a走到另一个点b且必须经过根节点的话,那么走过的距离就是dist[a]+dist[b],但是我们并不用要经过根节点,我们是要求走过的路最短,所以我们可以省去经过根节点的那段路,即dist[a]和dist[b]中离根节点最近的那段路*2( *2是因为去往根节点在离开根节点这段距离是一样的),(假设是dist[b]离根节点近)那么就变成了:dist[a]+dist[b]-2 *dist[b]==dist[a]-dist[b]。这个就是两个点的最短路距离了,我们只用判断dist[a]-dist[b]的奇偶性即可。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 5e4 + 50;
const int MOD = 1e9 + 7;

inline int read() {
    int x = 0; char ch = getchar();
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x;
}

inline void write(int x) {
    if (x > 9) write(x / 10);
    putchar(x % 10 | '0');
}

int main()
{
    int n, m, x, y;
    n = read(), m = read();
    vector<int>dist(n + 1);
    unordered_map<int, vector<int>>p;
    for (int i = 1; i < n; i++)
    {
        x = read(), y = read();
        p[x].push_back(y);
        p[y].push_back(x);
    }
    queue<int>que;
    que.push(1);
    int ans = 1;
    while (!que.empty())
    {
        int len = que.size();
        for (int i = 0; i < len; i++)
        {
            int a = que.front();
            que.pop();
            for (auto i : p[a])
            {
                if (dist[i] == 0)
                {
                    que.push(i);
                    dist[i] = ans;
                }
            }
        }
        ans++;
    }
    while (m--)
    {
        x = read(), y = read();
        if ((abs(dist[x] - dist[y])) % 2 == 1)
        {
            puts("Road");
        }
        else
        {
            puts("Town");
        }
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值