【cf1283F】F. DIY Garland(构造)

传送门

题意:
现有一颗有根树,每个结点\(i\)有权值\(2^i\),每条边有权值为这条边连接的深度较大的结点的子树权值和。
但现在并不知道这颗树的形态。
现在只会给出以下信息:按照边的权值从大到小进行排序,然后依次给出每条边的父亲结点。
现在要确定这颗树的形态。

思路:
假设每次给出的父亲结点为\(p_i\),那么显然\(p_1\)为根节点。
注意,因为每个结点的权值为\(2^i\),那么可以知道我们会依次找\(2^n,2^{n-1},\cdots,2^1\)这些结点的位置。根据这一点,可以直接分情况讨论:

  • 记录一个变量\(now\)为目前需要找的结点。
  • 若\(p_i\)已存在,说明要新产生一颗子树,并且\(now\)结点已找到,为\(p_{i-1}\)的儿子;
  • 若\(p_i\)不存在,那么就是继续在寻找\(now\)结点,继续往当前子树深入即可。

注意用一个数组来标记结点是否找到。
细节见代码:

/*
 * Author:  heyuhhh
 * Created Time:  2020/3/1 15:51:31
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 2e5 + 5;

int n;
int a[N];
bool chk[N];

void run(){
    vector <pii> edges;
    for(int i = 1; i < n; i++) cin >> a[i];
    int rt = a[1];
    chk[rt] = true;
    cout << rt << '\n';
    int now = n;
    while(chk[now]) --now;
    for(int i = 2; i < n; i++) {
        if(!chk[a[i]]) {
            edges.push_back(MP(rt, a[i]));
            rt = a[i];
            chk[rt] = true;
        } else {
            edges.push_back(MP(rt, now));
            chk[now] = true;
            rt = a[i];
        }
        while(chk[now]) --now;
    }
    assert(now > 0);
    edges.push_back(MP(rt, now));
    for(auto it : edges) {
        cout << it.fi << ' ' << it.se << '\n';
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    while(cin >> n) run();
    return 0;
}

原文地址:https://www.cnblogs.com/heyuhhh/p/12450806.html

时间: 2024-10-10 00:11:01

【cf1283F】F. DIY Garland(构造)的相关文章

CF-div3-611-F. DIY Garland 优先队列 构造树

思路 参考队友博客:https://www.cnblogs.com/AaronChang/p/12129861.html 思考如何构造一个树:(亮度低与重要度低)的二者匹配: 什么时候重要度低,就叶节点开始(从下到上). 所以,从叶节点出发,往上构造,度数为0的就是叶节点加入优先队列,与重要度从小到大相匹配. 代码 #include<bits/stdc++.h> using namespace std; typedef long long ll; /* 思考如何构造一个树:权值小的先匹配,什么

使用 F# 列表

在 C# 中使用 F# 的列表,是完全可能的,但是,我建议不要用,因为,只要再做一点,就会使事情在 C# 看来更加自然.例如,把列表转换成数组很简单,用List.toArray 函数:转换成System.Collections.Generic.List,用 new ResizeArray<_>()构造函数:转换成System.Collections.Generic.IEnumerable,用 List.toSeq 函数.这些类型的使用对于C# 程序员来说,实在是太简单了,特别是System.A

HDU 1575 &amp;&amp; 1757 矩阵快速幂&amp;&amp;构造矩阵入门

HDU 1575 Tr A Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2912    Accepted Submission(s): 2167 Problem Description A为一个方阵,则Tr A表示A的迹(就是主对角线上各项的和),现要求Tr(A^k)%9973. Input 数据的第一行是一个T,表示有T组数据.每组

hdu1757 构造矩阵

Lele now is thinking about a simple function f(x). If x < 10 f(x) = x.If x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10);And ai(0<=i<=9) can only be 0 or 1 . Now, I will give a0 ~ a9 and two positive integers k and m

MT【219】构造二次函数

(2012北大保送)已知$f(x)$是二次函数,且$a,f(a),f(f(a)),f(f(f(a)))$是正项等比数列;求证:$f(a)=a$ 构造二次函数$f(x)=qx$,则$a,f(a),f(f(a))$是该二次函数的三个根,故他们当中必有两个相等,从而易得$q=1$,故$f(a)=a$ 原文地址:https://www.cnblogs.com/mathstudy/p/9695263.html

矩阵经典题目七:Warcraft III 守望者的烦恼(矩阵加速递推)

https://www.vijos.org/p/1067 很容易推出递推式f[n] = f[n-1]+f[n-2]+......+f[n-k]. 构造矩阵的方法:构造一个k*k的矩阵,其中右上角的(k-1)*(k-1)的矩阵是单位矩阵,第k行的每个数分别对应f[n-1],f[n-2],,f[n-k]的系数.然后构造一个k*1的矩阵,它的第i行代表f[i],是经过直接递推得到的.设ans[][]是第一个矩阵的n-k次幂乘上第二个矩阵,f[n]就是ans[k][1]. 注意:用__int64 #in

【矩阵快速幂 】Codeforces 450B - Jzzhu and Sequences (公式转化)

[题目链接]click here~~ [题目大意] Jzzhu has invented a kind of sequences, they meet the following property: You are given x and y, please calculate fn modulo1000000007(109?+?7). [解题思路] /*A - Jzzhu and Sequences Codeforces 450B - Jzzhu and Sequences ( 矩阵快速幂 )

Fast Walsh-Hadamard Transform——快速沃尔什变换

模板题: 给定$n = 2^k$和两个序列$A_{0..n-1}$, $B_{0..n-1}$,求 $$C_i = \sum_{j \oplus k = i} A_j B_k$$ 其中$\oplus$是某一满足交换律的位运算,要求复杂度$O(nlogn)$. 快速沃尔什变换: 这是什么东西?有用吗?请参阅SDOI2017r2d1-cut. 看到这个大家是不是立刻想到了快速傅里叶变换? $$C_i = \sum_{j + k = i} A_j B_k$$ 我们来想想离散傅里叶变换的本质. $$\b

AC自动机 - 学习笔记

AC自动机 ----多个模板的字符串匹配 字典树Trie加上失配边构成 struct ACauto { int ch[MAXN][26]; int size; int f[MAXN],last[MAXN],val[MAXN],cnt[MAXN]; //val用来在字典树中的模板串末尾处标记,标记为模板串的序号(从1开始) //last后缀链接:结点J沿着失配指针往回走时,遇到的下一个单词尾结点. void init()//初始化 { size=1;//字典树中的节点数 memset(ch[0],