传送门

思路:

我们需要抓住唯一的重要信息点"ci",我的做法也是在猜想和尝试中得出的,之后再验证算法的正确性。

我们在构造中发现,如果树上出现了相同的数字,则会让树的构造变得不清晰。

我们尝试用不同的数值a[1]~a[n]去构造树,我们唯一知道的信息就是"ci",如果a[1]~a[n] = 1~n(从小到大排序),则我们容易确定root的数值id[root] = a[c[root] + 1]。为什么?因为我们有1~n这n个数字,如果我们id[root] = a[c[root] + 1],则root下面的点,无论怎么放置这n-1个数字都满足c[root]。如果该root的左边第一个son节点的c[x] = t,则id[x]为第c[x] + 1个数字(因为id[root]被使用了)好像也行的通(红字带入也行得通),然后我按着从左开始的dfs序模拟,发现问题就解决了,这样的方法是行的通的。为什么?模拟了之后才发现,因为我们选的是不同的数字,我们如果按着从左的dfs序一个个的解决子树,只要有足够的不同数字,则该方法一定是可以构造出当前子树的信息(带入红字理解),即子树之间独立不影响。用这个构造方法之前只需要先判断下所有的ci是不是合法,即该点下面如果只有x个数字,c[now]>x就是不合法的。代码下面有个样例,模拟下就理解了。

  1 #include <iostream>
2 #include <algorithm>
3 #include <cstdio>
4 #include <cstring>
5 #include <queue>
6 #include <string>
7 #include <map>
8 #include <set>
9
10 using namespace std;
11
12 const int N = 2e3 + 10;
13 vector<int > E[N];
14 set<int > hav;
15 int son[N], id[N];
16 int error;
17
18 int fun (int now, int pre)
19 {
20 int sn = 0;
21 for(auto to : E[now]) {
22 if(to == pre) continue;
23 sn += fun(to, now);
24 }
25
26 if(son[now] - 1 > sn) error = 1;
27 return sn + 1;
28 }
29
30 void dfs (int now, int pre)
31 {
32 if(son[now] > hav.size()) { error = 1; return; }
33 else {
34 int tot = 0;
35 for(auto& x: hav) {
36 ++tot;
37 if(tot == son[now]) {
38 id[now] = x;
39 // cout << x << endl;
40 hav.erase(x);
41 break;
42 }
43 }
44 }
45
46 for(auto to : E[now]) {
47 if(to == pre) continue;
48 dfs(to, now);
49 if(error) return;
50 }
51 }
52
53 void solve()
54 {
55 int n, root;
56 scanf("%d", &n);
57 for(int i = 1; i <= n; ++i) {
58 int x, cnt;
59 scanf("%d%d", &x, &cnt);
60 if(x != 0) {
61 E[i].push_back(x);
62 E[x].push_back(i);
63 } else root = i;
64 son[i] = cnt + 1;
65 }
66
67 for(int i = 1; i <= n; ++i) { hav.insert(i); }
68
69 error = 0;
70 fun(root, 0);
71 if(error) {
72 printf("NO\n");
73 return;
74 }
75 dfs(root, 0);
76 if(error) { printf("NO\n"); }
77 else {
78 printf("YES\n");
79 for(int i = 1; i <= n; ++i) { printf("%d ", id[i]); }
80 printf("\n");
81 }
82 }
83
84 int main()
85 {
86
87 solve();
88
89 return 0;
90 }
91 /*
92 13
93 0 5
94 1 2
95 2 0
96 2 1
97 4 0
98 4 1
99 6 0
100 6 0
101 1 1
102 9 0
103 9 2
104 11 0
105 11 0
106
107 */

D. Numbers on Tree(构造)【CF 1287】的更多相关文章

  1. UVA10006 - Carmichael Numbers(筛选构造素数表+高速幂)

    UVA10006 - Carmichael Numbers(筛选构造素数表+高速幂) 题目链接 题目大意:假设有一个合数.然后它满足随意大于1小于n的整数a, 满足a^n%n = a;这种合数叫做Ca ...

  2. HDU 5573 Binary Tree 构造

    Binary Tree 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5573 Description The Old Frog King lives ...

  3. Codeforces Round #319 (Div. 1) B. Invariance of Tree 构造

    B. Invariance of Tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/576/ ...

  4. AIM Tech Round 4 (Div. 1) C - Upgrading Tree 构造 + 树的重心

    C - Upgrading Tree 我发现我构造题好弱啊啊啊. 很明显能想到先找到重心, 然后我们的目标就是把所有点接到重心的儿子上,让重心的儿子子树变成菊花图, 这个先把重心到儿子的边连到 i , ...

  5. 2020牛客暑期多校训练营 第二场 C Cover the Tree 构造 贪心

    LINK:Cover the Tree 最受挫的是这道题,以为很简单 当时什么都想不清楚. 先胡了一个树的直径乱搞的贪心 一直过不去.后来意识到这类似于最经典长链剖分优化贪心的做法 然后那个是求最大值 ...

  6. CF1129E Legendary Tree 构造

    传送门 神树可还行 我们令\(1\)为树根,那么如果要询问\(x\)是否在\(y\)子树中,就令\(S = \{1\} , T = \{x\} , u = y\),询问一下就可以知道了. 那么考虑先构 ...

  7. [CF1311E] Construct the Binary Tree - 构造

    Solution 预处理出 \(i\) 个点组成的二叉树的最大答案和最小答案 递归做,由于只需要构造一种方案,我们让左子树大小能小就小,因此每次从小到大枚举左子树的点数并检验,如果检验通过就选定之 现 ...

  8. Dividing the numbers CodeForces - 899C (构造)

    大意: 求将[1,n]划分成两个集合, 且两集合的和的差尽量小. 和/2为偶数最小差一定为0, 和/2为奇数一定为1. 显然可以通过某个前缀和删去一个数得到. #include <iostrea ...

  9. 2015多校第7场 HDU 5379 Mahjong tree 构造,DFS

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5379 题意:一颗n个节点n-1条边的树,现在要给每个节点标号(1~n),要求:(1)每一层的兄弟节点的 ...

随机推荐

  1. Java导出Pdf格式表单

    前言   作为开发人员,工作中难免会遇到复杂表单的导出,接下来介绍一种通过Java利用模板便捷导出Pdf表单的方式 模拟需求   需求:按照下面格式导出pdf格式的学生成绩单 准备工作 Excel软件 ...

  2. Maven魔法堂:安装Oracle JDBC Driver依赖的那些坑

    前言 由于Oracle并没有向公开Maven仓库提供任何Oracle JDBC Driver的Jar包,因此我们无法像MySQL.SQLite等那么轻松直接通过Maven加载依赖. 而手动下载Orac ...

  3. Zookeeper源码(启动+选举)

    简介 关于Zookeeper,目前普遍的应用场景基本作为服务注册中心,用于服务发现.但这只是Zookeeper的一个的功能,根据Apache的官方概述:"The Apache ZooKeep ...

  4. 多服务器使用Docker设置一主一从三哨兵redis(完整)

    本来应该续之前那篇博客Docker配置redis哨兵模式--多服务器·上写一个下篇的,但是忽然意识到应该将必要的环境打包为一个基础镜像,在此基础上建立与redis有关的镜像,这样既能够快速打包,又能够 ...

  5. GROUP BY 分组后得到最新即时间最大的一条数据(需添加limit才可生效)

    当使用GROUP BY 分组,默认返回的数据是组中最小的记录即id最小的数据, 当开发中经常会需要分组后将最新的数据放在前面, 为了实现需求,使用了嵌套查询,分别使用order by来排序 SELEC ...

  6. 【线上问题排查技巧】动态修改LOGGER日志级别

    前言 大多数情况下,我们会在打印日志时定义日志的LOGGER级别,用来控制输出的信息范围. 一方面,过多的输出会影响查看日志的效率,另一方面,过少的日志让问题定位变得困难. 但当线上出现问题时,线上容 ...

  7. 跟我一起学Redis之Redis事务简单了解一下

    前言 关系数据库中的事务,小伙伴们应该是不陌生了,不管是在开发还是在面试过程中,总有两个问题逃不掉: 说说事务的特性: 事务隔离级别是怎么一回事? 事务处理不好,数据就可能不准确,最终就会导致业务出问 ...

  8. 使用switch计算出某年某月某日是今年的第几天,输出一直是当月天数

    package com.cx.Switch; import java.util.Scanner; /** * 计算出某年某月某日是今年的第几天 * 使用switch */ public class S ...

  9. 内网渗透 day7-linux信息收集

    linux信息搜集 目录 1. linux信息搜集 2. nmap漏洞复现 3. msf linux模块反弹shell 1. linux信息搜集 id 查看当前用户的权限和所在的管理组 python ...

  10. Java8 新特性 —— Stream 流式编程

    本文部分摘自 On Java 8 流概述 集合优化了对象的存储,大多数情况下,我们将对象存储在集合是为了处理他们.使用流可以帮助我们处理对象,无需迭代集合中的元素,即可直接提取和操作元素,并添加了很多 ...