• [CF1283F] DIY Garland


    Description

    给定一棵树,编号为 i 的点权值为 2^i,定义一条边的权值为这条边链接的两个点中深度较大的点的子树的点权和。给出总点数 n,按照边权从大到小给出每条边的深度较浅的点的编号,要求构造原树。

    Solution

    边权即子树和,那么同一条直链上的边权单调,且根处最大,叶子处最小。因此排在整个序列末尾的一定是叶子结点相关的边。一个结点时叶子结点,当且仅当它不曾在原序列中出现。

    考虑一个构造过程,每一步我们会定出一条边,我们一定希望我们要定出的这条边边权最小,因此对于所有叶子结点(挂着他们的子树),维护小顶堆,权值为子树点权和,但是这样太难维护了,所以点权和直接用点自身的编号替代(题目条件的使用)。

    我们按原序列倒序遍历所有的点,对于每个点,弹出堆顶与其连边(相当于一个非叶子和叶子的配对过程),配对后的点其实就被“删除”了,这个时候如果产生了新的叶子,那么也需要将其加入堆中。

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long 
    const int N = 1000005;
    
    
    int n,a[N],root,d[N];
    
    priority_queue <int,vector<int>,greater<int>> heap;
    
    signed main()
    {
        ios::sync_with_stdio(false);
    
        cin>>n;
        for(int i=2;i<=n;i++) cin>>a[i];
    
        root=a[2];
    
        cout<<root<<endl;
    
        for(int i=2;i<=n;i++) d[a[i]]++;
    
        for(int i=1;i<=n;i++) if(d[i]==0) heap.push(i);
        for(int i=n;i>=2;i--)
        {
            int p=heap.top();
            heap.pop();
            cout<<p<<" "<<a[i]<<endl;
            d[a[i]]--;
            
            if(d[a[i]]==0) heap.push(a[i]);
        }
    }
    
  • 相关阅读:
    MSSQL·FOR XML PATH语法转义尖括号解决方案
    代码上传Github后乱码解决方案
    MSSQL·CONCAT函数的基础使用
    使用URL快捷方式提高效率
    数组逆序
    C++默认拷贝构造
    HO引擎近况20220512
    老猿谈谈对Tensorflow的理解
    学习笔记——Python中的IO问题理解
    PHP接口报错:Unable to init from given binary data
  • 原文地址:https://www.cnblogs.com/mollnn/p/14043993.html
Copyright © 2020-2023  润新知