构造,贪心,拓扑排序变形——cf1283F

/*
题意:一棵有根树,每个结点的权重为2^i,每条边的权重为其下子树结点的权重和
    现在按边权降序排序,每条边记录高度大的那个点,得到一个长度为n-1的序列
    根据这个序列构造出一棵合法的树
性质:(fa[fa[u]],fa[u])必排在(fa[u],u)前面
可以自底向上构造这棵树,先把叶子结点放进set里,然后倒序遍历数列,每次取出一个叶子结点到它的父节点里去,同时更新父亲结点的权值 
    如果父节点下的结点都被塞进去了,那么把这个父亲结点放进set,整个过程有点像拓扑排序 
*/ 
#include<bits/stdc++.h>
using namespace std;
#define N 200005

int n,a[N],son[N],Max[N];
set<pair<int,int> >s;
set<pair<int,int> >::iterator it;
pair<int,int>edge[N];

int main(){
    cin>>n;
    for(int i=1;i<n;i++)cin>>a[i],son[a[i]]++;
    for(int i=1;i<=n;i++)Max[i]=i;
    for(int i=1;i<=n;i++)if(!son[i])s.insert(make_pair(Max[i],i));
    for(int i=n-1;i>=1;i--){
        it=s.begin();
        edge[i].first=a[i];
        edge[i].second=(*it).second;
        son[a[i]]--;
        Max[a[i]]=max(Max[(*it).second],Max[a[i]]);
        if(son[a[i]]==0)
            s.insert(make_pair(Max[a[i]],a[i]));
        s.erase(it);
    }
    cout<<a[1]<<'
';
    for(int i=1;i<n;i++)
        cout<<edge[i].first<<" "<<edge[i].second<<'
';
} 
原文地址:https://www.cnblogs.com/zsben991126/p/12284104.html