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]);
        }
    }
    
  • 相关阅读:
    szoj657 【AHSDFZNOI 7.2 WuHongxun】Odd
    cogs2652 秘术「天文密葬法」
    bzoj1026 [SCOI2009]windy数
    bzoj1862/1056: [Zjoi2006]GameZ游戏排名系统
    java-PreparedStatement的用法
    java-JDBC登录注册代码
    java-String Date Calendar之间的转换
    java-如何用eclipse打包jar
    java-通过JDBC操作数据库
    java-JDBC配置驱动程序
  • 原文地址:https://www.cnblogs.com/mollnn/p/14043993.html
Copyright © 2011-2022 走看看