zoukankan      html  css  js  c++  java
  • [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]);
        }
    }
    
  • 相关阅读:
    Bridge Design Pattern
    终于写了个自己的简单MVC框架!
    c 第1章的习题 列表 ! :)
    如何创建 linux 下的计划任务运行 php 文件?
    c 的开篇(自学 c 语言)
    一连串问题,都和.net framework有关
    信号与信号量的区别[转]
    永久设置SecureCRT的背景色和文字颜色方案[转]
    do...while(0)的妙用 【转】
    给Ubuntu软件升级命令 [转]
  • 原文地址:https://www.cnblogs.com/mollnn/p/14043993.html
Copyright © 2011-2022 走看看