专栏文章

CF1283F 题解

CF1283F题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minxwvs2
此快照首次捕获于
2025/12/02 10:09
3 个月前
此快照最后确认于
2025/12/02 10:09
3 个月前
查看原文

题意

一棵有 nn 个点的树,对于一条边,记该边深度较大的一个端点为 uu,该边的权值为 2v\sum 2^v,其中 vvuu 的子树中的点的编号。按边权从大到小的顺序给出每条边的深度较浅的端点,求树的根节点以及每条边的端点。

思路

由于点的编号是不重复的,对于两条没有祖孙关系的边,一条边的权值比另一条边大等价于这条边的子树中的点的编号最大值比另一条边的大。
可以用小根堆维护每个已经确定完边的子树中的树根以及子树中的最大值。初始时能确定哪些点是叶节点,将叶节点加入堆中。
按权值从小到大考虑每条边,确定当前边的另一端点为堆顶子树的根。

代码

CPP
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,a[200005],cnt[200005];
struct Node{
	int maxn,top;
	bool operator < (const Node &y)const{
		return maxn>y.maxn;
	}
};
priority_queue<Node>q;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<n;i++){
		cin>>a[i];
		cnt[a[i]]++;
	}
	for(int i=1;i<=n;i++){
		if(!cnt[i])q.push({i,i});
	}
	cout<<a[1]<<"\n";
	for(int i=n-1;i>=1;i--){
		Node k=q.top();
		q.pop();
		cout<<a[i]<<" "<<k.top<<"\n";
		cnt[a[i]]--;
		if(!cnt[a[i]])q.push({max(k.maxn,a[i]),a[i]}); 
	}
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...