题解:LG_P12652 [KOI 2024 Round 2] 拔树游戏

联考 T1,虽然简单,但是学姐骂的对

题意

其实看题面也看得懂。

从根节点(初始为 \(1\) 号节点)开始,向儿子中权值最小的儿子走,直到走到叶子节点,把根节点删除,并将整个链向根移一个节点。像这样操作 \(n\) 次,每次操作前输出根节点的权值。

6 分

暴力会吧。

16 分

第一个性质手玩一下就会发现是直接从 \(1\)\(n\) 输出。

27 分

第二个性质依然手玩,发现直接 dfs,每次向儿子中权值最小的儿子走,每到一个节点就输出这个节点的权值。

50 分

考场上没看懂这一档部分分的用处。

100 分

考虑直接拓展性质 2 的做法,将 dfs 变为 bfs,并将队列换成小根堆维护就好了。

考虑这为什么是对的。

在第一次操作时,就是把根节点的所有儿子中权值最小的移到根节点,而第二次操作,就是把原先根节点的所有儿子以及原先根节点的所有儿子中权值最小的节点的儿子中权值最小的移到根节点,接下来的操作依此类推。

我们发现每操作一次,就把整个范围中权值最小的节点删除,并向它的儿子节点扩大范围,注意到这和 bfs 或者说 dij 很像对吧,而且我们还注意到所有节点的权值互不相同,于是我们类似 dij 用以权值为关键字的小根堆代替 bfs 的队列,每次输出并弹出堆顶,然后将堆顶的儿子丢入队列中就可以完美维护了。

代码

//by _Rimuru_ uid:1114894
#include<bits/stdc++.h>
using namespace std;
/*
快读快写不给
*/
const int N=3e5+10;
int n;
int p[N];
int a[N];
vector<int>e[N];
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q;
signed main(){
    n=read();
    for(int i=2;i<=n;i++){
        p[i]=read();
        e[p[i]].push_back(i);
    }
    for(int i=1;i<=n;i++)
        a[i]=read();
  	q.push({a[1],1});
  	while(!q.empty()){
        int u=q.top().second;
        write(q.top().first,1);
        q.pop();
        for(int v:e[u])
            q.push({a[v],v});
  	} 
    return 0;
}
posted @ 2025-09-02 15:40  BriskCube  阅读(7)  评论(0)    收藏  举报