D. Apple Tree Traversing 【Codeforces Round 1023 (Div. 2)】

D. Apple Tree Traversing

题目大意

有一个包含 n n n 个节点的苹果树,初始时每个节点上有一个苹果。你有一张纸,初始时纸上没有任何内容。

你需要通过以下操作遍历苹果树,直到所有苹果都被移除:

• 选择一个苹果路径 ( u , v ) (u, v) (u,v)。当且仅当路径 ( u , v ) (u, v) (u,v) 上的每个节点都有苹果时,该路径才称为苹果路径。

• 设 d d d 为路径上的苹果数量,在纸上按顺序写下三个数字 ( d , u , v ) (d, u, v) (d,u,v)。

• 然后移除路径 ( u , v ) (u, v) (u,v) 上的所有苹果。

这里的路径 ( u , v ) (u, v) (u,v) 指的是从 u u u 到 v v v 的唯一最短路径上的所有节点序列。

设纸上的数字序列为 a a a。你的任务是找到字典序最大的可能序列 a a a。

思路:

根据字典序的需求,要优先找最长的路径,然后路径的两个端点序号要最大。 那么可以通过两次dfs找直径的方式,找序号最大的最远点。每次找完一条直径就可以把树分成若干子树,继续在子树里找直径即可,最后把找到的直径排序输出。这是很容易想到的解法,时间复杂度是 O ( n n ) O(n\sqrt{n}) O(nn )的。

(证明过程其实很经典,因为每次移除的直径严格递减, k ⋅ ( k + 1 ) 2 ≤ n \dfrac{k \cdot (k + 1)}{2} \le n 2k⋅(k+1)≤n,进而推得 k ≤ 2 ⋅ n k \le 2 \cdot \sqrt{n} k≤2⋅n )

具体实现见代码,dfs函数保存路径用pre前驱数组,避免用stl被卡常。

代码:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
#define int long long
#define pb push_back
#define pii pair<int, int>
#define FU(i, a, b) for (int i = (a); i <= (b); ++i)
#define FD(i, a, b) for (int i = (a); i >= (b); --i)
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5 + 5, MAXN = maxn;

int n;
bool vis[maxn] = {};
vector<int> ed[maxn];

struct way {
    int len, u, v;
    way(int a, int b, int c) : len(a), u(b), v(c) {};
    bool operator<(const way &o) const {
        if (len == o.len) {
            if (u == o.u)
                return v < o.v;
            return u < o.u;
        }
        return len < o.len;
    }
};
int p[maxn];
pair<int, int> dfs1(int u, int par) { // find farest max
    pair<int, int> res = {1, u};
    p[u] = par;
    for (int v : ed[u]) {
        if (v != par && !vis[v]) {
            auto tmp = dfs1(v, u);
            tmp.first += 1;
            if (tmp.first > res.first ||
                (tmp.first == res.first && tmp.second > res.second))
                res = tmp;
        }
    }
    return res;
}

void solve() {
    cin >> n;
    FU(i, 1, n) {
        ed[i].clear();
        vis[i] = 0;
    }
    FU(i, 1, n - 1) {
        int u, v;
        cin >> u >> v;
        ed[u].pb(v);
        ed[v].pb(u);
    }
    priority_queue<way> ans;
    for (int i = n; i >= 1; i--) {
        if (vis[i])
            continue;
        FU(j, 1, n) p[j] = -1;

        auto [d1, j] = dfs1(i, -1);
        auto [d2, k] = dfs1(j, -1);
        ans.push(way(d2, max(j, k), min(j, k)));
        while (k != -1) {
            vis[k] = true;
            k = p[k];
        }
        if (vis[i] == 0) i++; //如果当前点没有标记就重复遍历,不然会略掉i点
    }
    while (!ans.empty()) {
        auto e = ans.top();
        ans.pop();
        cout << e.len << " " << e.u << " " << e.v << " ";
    }
    cout << endl;
}

signed main() {
#ifdef ONLINE_JUDGE
#else
    freopen("../in.txt", "r", stdin);
#endif
    cin.tie(0)->ios::sync_with_stdio(0);
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}
相关推荐
-qOVOp-几秒前
zst-2001 历年真题 设计模式
java·算法·设计模式
yaoshengvalve15 分钟前
V型球阀材质性能深度解析:专攻颗粒、料浆与高腐蚀介质的工业利器-耀圣
开发语言·网络·数据结构·c++·安全·材质
evolution_language16 分钟前
LintCode第68题-二叉树的前序遍历,第67题-二叉树的后序遍历
数据结构·算法·新手必刷编程50题
passionSnail27 分钟前
《用MATLAB玩转游戏开发:从零开始打造你的数字乐园》基础篇(2D图形交互)-俄罗斯方块:用旋转矩阵打造经典
算法·matlab·矩阵·游戏程序·交互
yxc_inspire28 分钟前
C++STL在算法竞赛中的应用详解
c++·算法·stl
James. 常德 student31 分钟前
leetcode-hot-100(哈希)
算法·leetcode·哈希算法
金融小师妹1 小时前
量化解析美英协议的非对称冲击:多因子模型与波动率曲面重构
大数据·人工智能·算法
是店小二呀1 小时前
【算法-哈希表】常见算法题的哈希表套路拆解
数据结构·c++·算法·散列表
jiunian_cn1 小时前
【c++】多态详解
java·开发语言·数据结构·c++·visual studio
炯哈哈1 小时前
【上位机——MFC】对话框
开发语言·c++·mfc·上位机