C0214 拔树游戏 题解

这道题挺有趣的。

不难发现每一次的拔树操作就是对一个根节点的所有子节点(只是下一层)取最小点权的那个节点取代本身。同时发现,因为每次取的节点都是最小的,所以在堆里的优先度是一定大于同一层的其他节点,这跟直接把这个节点往上移成为其他曾经同层的节点的父亲所带来的优先度是一致的,所以可以直接用一个优先队列维护树里的节点,然后借以广搜的想法遍历即可。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
const int N = 3e5+100;

struct node {
    int point, val;
    bool operator < (const node &tmp) const { return tmp.val < val; }
};

vector <int> p[N];

void solve () {
    int n; cin >> n;
    vector <int> a(n+1);
    for (int i = 2;i <= n;i++) {
        int tmp; cin >> tmp;
        p[tmp].push_back(i);
    }
    for (int i = 1;i <= n;i++) cin >> a[i];
    priority_queue <node> q;
    vector <bool> vis(n+1);
    auto bfs = [&](int s) -> void {
        q.push({s, a[s]});
        vis[s] = true;
        while (!q.empty()) {
            auto [point, val] = q.top();
            cout << a[point] << "\n";
            q.pop();
            vis[point] = false;
            for (auto to : p[point]) q.push({to, a[to]});
        }
    };
    bfs(1);
}

int main () {
    freopen("tree.in", "r", stdin);
    freopen("tree.out", "w", stdout);
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int _ = 1;
    while (_--) solve();
    return 0;
}