Codeforces Round 947 (Div. 1 + Div. 2) D. Paint the Tree 题解 DFS

Paint the Tree

题目描述

378QAQ has a tree with n n n vertices. Initially, all vertices are white.

There are two chess pieces called P A P_A PA and P B P_B PB on the tree. P A P_A PA and P B P_B PB are initially located on vertices a a a and b b b respectively. In one step, 378QAQ will do the following in order:

  1. Move P A P_A PA to a neighboring vertex. If the target vertex is white, this vertex will be painted red.
  2. Move P B P_B PB to a neighboring vertex. If the target vertex is colored in red, this vertex will be painted blue.

Initially, the vertex a a a is painted red. If a = b a=b a=b, the vertex a a a is painted blue instead. Note that both the chess pieces must be moved in each step. Two pieces can be on the same vertex at any given time.

378QAQ wants to know the minimum number of steps to paint all vertices blue.

输入描述

Each test contains multiple test cases. The first line contains the number of test cases t t t ( 1 ≤ t ≤ 1 0 4 1\leq t\leq 10^4 1≤t≤104). The description of the test cases follows.

The first line of each test case contains one integer n n n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 1\leq n\leq 2\cdot 10^5 1≤n≤2⋅105).

The second line of each test case contains two integers a a a and b b b ( 1 ≤ a , b ≤ n 1\leq a,b\leq n 1≤a,b≤n).

Then n − 1 n - 1 n−1 lines follow, each line contains two integers x i x_i xi and y i y_i yi ( 1 ≤ x i , y i ≤ n 1 \le x_i,y_i \le n 1≤xi,yi≤n), indicating an edge between vertices x i x_i xi and y i y_i yi. It is guaranteed that these edges form a tree.

It is guaranteed that the sum of n n n over all test cases does not exceed 2 ⋅ 1 0 5 2\cdot 10^5 2⋅105.

输出描述

For each test case, output the minimum number of steps to paint all vertices blue.

样例输入#1

复制代码
3
2
1 2
1 2
5
1 2
1 2
1 3
1 4
1 5
8
5 4
7 1
1 5
1 8
8 3
7 2
8 6
3 4

样例输出 #1

复制代码
2
8
13

原题

CF------传送门
洛谷------传送门

思路

先让棋子A与棋子B汇合,再让它们用最少的步数一起走过所有结点。这样的步数一定是最少的,因为将顶点涂成蓝色的前提是两棋子都经过某一点,而让两棋子相互靠近直到第一个结点被涂成蓝色便是最优的。值得注意的是,棋子A,B之间的相对位置存在两种情况:同步和异步。同步代表着两棋子可以在同一时间位于同一个结点上,使该结点变为蓝色;而异步代表着某一步中A棋子位于结点X上,只有在下一步时B棋子才有可能走到结点X上,并使该结点变为蓝色。

代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 2e5 + 6;
vector<int> e[maxn]; // e[i]存储以i为起点的所有有向边

void add(int x, int y) // 加无向边
{
    e[x].push_back(y);
    e[y].push_back(x);
}

int a, b;
deque<int> path; // 记录两颗棋子汇合的路径
int st = -1;     // 两颗棋子最快汇合后的点(也是dfs求max_dis的起点)
int step = 0;    // 汇合所需步数
int extra = 0;   // 两个棋子不可能位于同一个结点的情况(即两棋子异步),此时需要补充1步
void dfs1(int pos, int fa, int depth, int tag)
{
    if (st != -1) // 如果已找到答案,快速返回
        return;
    for (int i = 0; i < e[pos].size(); i++)
    {
        int to = e[pos][i];
        if (to == tag)
        {
            step = (depth + 1) / 2;
            if (path.size() % 2 == 0) // 两棋子异步(即两棋子初始时距离为奇数,也就是最短路径上的结点为偶数个的情况)
            {
                extra = 1;          // 补充1步
                path.push_front(a); // 特殊照顾一下两棋子初始时距离为1的情况,因为这种情况下st为a,但是path路径在dfs时并没有保存a结点
                st = path[step];
            }
            else // 两棋子同步(即两棋子初始时距离为偶数,也就是最短路径上的结点为奇数个的情况)
            {
                st = path[step - 1];
            }
            return;
        }
        if (to == fa)
            continue;
        path.push_back(to);
        dfs1(to, pos, depth + 1, tag);
        path.pop_back(); // 回溯
    }
}

int max_dis = 0; // 起点st到其他点的所有距离中的最远距离
void dfs2(int pos, int fa, int depth)
{
    max_dis = max(max_dis, depth); // 维护最远距离即可
    for (int i = 0; i < e[pos].size(); i++)
    {
        int to = e[pos][i];
        if (to == fa)
            continue;
        dfs2(to, pos, depth + 1);
    }
}

void solve()
{
    int n;
    cin >> n;
    cin >> a >> b;
    int x, y;
    for (int i = 1; i <= n - 1; i++)
    {
        cin >> x >> y;
        add(x, y);
    }
    if (a != b)
        dfs1(a, 0, 0, b);
    else
        st = a;
    dfs2(st, 0, 0);
    // 2 * (n - 1) - max_dis是用到了一个结论:从树中的一个结点开始走,走过树上所有结点至少需要2 * (n - 1) - max_dis步
    cout << step + 2 * (n - 1) - max_dis + extra << '\n';

    // 初始化,为了处理下一组测试数据
    for (int i = 1; i <= n; i++)
    {
        e[i].clear();
    }
    path.clear();
    st = -1;
    dis = 0;
    max_dis = 0;
    extra = 0;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);

    int t;
    cin >> t;
    while (t--)
        solve();

    return 0;
}
相关推荐
MC皮蛋侠客1 天前
Google Test 单元测试指南
c++·单元测试·google test
艾莉丝努力练剑1 天前
【Linux:文件】Ext系列文件系统进阶
linux·运维·服务器·c++·文件系统·文件io·ext
kkeeper~1 天前
0基础C语言积跬步之数据在内存中的存储
c语言·数据结构·算法
wabs6661 天前
关于贪心算法的一些自我总结【力扣45.跳跃游戏II】【灵感来源:代码随想录】
算法·贪心算法·复盘
2401_876964131 天前
【湖北专升本】2026湖北专升本真题PDF+备考资料汇总
数据结构·人工智能·经验分享·深度学习·算法·计算机视觉
basketball6161 天前
C++ NULL 和 nullptr 区别 以及 nullptr 的核心实现
java·开发语言·c++
嗝o゚1 天前
CANN GE 算子融合——融合算法与调度策略
算法·昇腾·cann·ge
小江的记录本1 天前
【JVM虚拟机】垃圾回收GC:垃圾回收算法:标记-清除、标记-复制、标记-整理、分代收集(附《思维导图》+《面试高频考点清单》)
java·jvm·后端·python·算法·安全·面试
Fre丸子_1 天前
自定义文件夹选取功能
c++
Ulyanov1 天前
用声明式语法重新定义Python桌面UI:QML+PySide6现代开发入门(一)
开发语言·python·算法·ui·系统仿真·雷达电子对抗仿真