@description@

对于一棵 n 个点的树,我们称两个点是相邻的当且仅当两个点的距离 <= 2。

现在给定 n 个集合,每一个集合表示树上某个点的相邻点是哪些。不过你不知道哪个集合对应哪个点。

现在这些集合构造出原树。保证至少存在一个解。如果多解,输出任意解即可。

原题传送门。

@solution@

两个点 x, y 对应的集合交集在树上仍然是一个连通块。

如果两个点 x, y 在树上距离 > 4,则它们集合交集为空。

如果两个点 x, y 在树上距离 = 4,则它们集合交集大小为 1。

如果两个点 x, y 在树上距离 = 3,则它们集合交集大小为 2。

如果两个点 x, y 在树上距离 = 2,则它们集合交集大小 >= 3。

如果两个点 x, y 在树上距离 = 1,则它们集合交集大小取决于 n:n = 2 时交集大小为 2;否则交集大小 >= 3。

集合交集为 2,该交集就对应着树上的一条边。

我们用 bitset 维护集合,并通过取交集找出所有的这种类型的边。

如果找不到一条这种类型的边,则只能是菊花图。特判即可。

否则,因为 n = 2 则已经找出了所有边,所以我们现在默认 n ≠ 2。

此时找出的边其实就是非叶结点之间形成的连通块,不妨称为新树。我们现在只需要把叶结点(度数为 1 的点)拼到父亲上面即可得到原树。

我们对于每个非叶结点,求出在新树中距离 <= 1 的点集,称为新邻集。

原图中叶结点原邻集 = 与该叶结点父亲相同的叶结点集合 + 父亲的新邻集。

如果新树只有一条边,此时两个点的新邻集相同,因此需要特判(父亲不同的叶结点分别连两个点)。

否则,每个点的新邻集互相不同。因此我们可以把原邻集与新树取交集,找到那个唯一的父亲。

不过注意到,当某个点在新树中度数为 1,此时它的原邻集与新树取交集也会对应一个新邻集。

此时该点一定连向某个原图中叶结点,且该叶结点的原邻集是该点的真子集。因此我们再判一下是否存在某个点的原邻集是当前点的原邻集的真子集即可。

复杂度 \(O(\frac{n^3}{\omega})\),实际上跑得挺快。

@accepted code@

  1. #include <bitset>
  2. #include <cstdio>
  3. #include <algorithm>
  4. using namespace std;
  5. int tag[1005], n;
  6. bitset<1005>a[1005], b[1005], c[1005], t, p;
  7. int main() {
  8. scanf("%d", &n);
  9. for(int i=1;i<=n;i++) {
  10. int k, x; scanf("%d", &k);
  11. for(int j=1;j<=k;j++)
  12. scanf("%d", &x), b[i][x] = 1;
  13. }
  14. for(int i=1;i<=n;i++)
  15. for(int j=i+1;j<=n;j++) {
  16. t = (b[i] & b[j]);
  17. // printf("%d %d : %d\n", i, j, t.count());
  18. if( t.count() == 2 ) {
  19. int x = t._Find_first(); t[x] = 0;
  20. int y = t._Find_first();
  21. a[x][y] = a[y][x] = 1;
  22. }
  23. }
  24. t = 0;
  25. for(int i=1;i<=n;i++)
  26. if( a[i].count() ) tag[i] = -1, t[i] = 1;
  27. for(int i=1;i<=n;i++) a[i][i] = 1;
  28. for(int i=1;i<=n;i++)
  29. for(int j=i+1;j<=n;j++)
  30. if( a[i][j] ) printf("%d %d\n", i, j);
  31. if( t.count() == 0 ) {
  32. for(int i=2;i<=n;i++)
  33. printf("%d %d\n", 1, i);
  34. }
  35. else if( t.count() == 2 ) {
  36. for(int x=1;x<=n;x++) {
  37. for(int y=x+1;y<=n;y++) {
  38. if( a[x][y] ) {
  39. bool flag = false;
  40. for(int i=1;i<=n;i++)
  41. if( b[i].count() != n ) {
  42. for(int j=1;j<=n;j++)
  43. if( b[i][j] ) {
  44. if( tag[j] == 1 ) break;
  45. else if( tag[j] != -1 ) {
  46. printf("%d %d\n", flag ? y : x, j);
  47. tag[j] = 1;
  48. }
  49. }
  50. flag = true;
  51. }
  52. }
  53. }
  54. }
  55. }
  56. else {
  57. for(int i=1;i<=n;i++) {
  58. c[i] = (b[i] & t);
  59. bool flag = true;
  60. for(int j=1;j<=n;j++)
  61. if( b[i] == b[j] ) {
  62. if( j < i ) {
  63. flag = false;
  64. break;
  65. }
  66. }
  67. else if( (b[i] & b[j]) == b[j] ) {
  68. flag = false;
  69. break;
  70. }
  71. if( flag ) {
  72. for(int j=1;j<=n;j++)
  73. if( c[i] == a[j] ) {
  74. for(int k=1;k<=n;k++)
  75. if( b[i][k] && tag[k] == 0 )
  76. printf("%d %d\n", j, k), tag[k] = 1;
  77. break;
  78. }
  79. }
  80. }
  81. }
  82. }

@details@

bitset 真好用。

一开始还想着二分图匹配找每个集合对应原树中哪一个点,不过发现找出来并不会更好做。

@codefoces - 566E@ Restoring Map的更多相关文章

  1. Codeforces.566E.Restoring Map(构造)

    题目链接 \(Description\) 对于一棵树,定义某个点的邻居集合为所有距离它不超过\(2\)的点的集合(包括它自己). 给定\(n\)及\(n\)个点的邻居集合,要求构造一棵\(n\)个点的 ...

  2. Codeforces 566E - Restoring Map(bitset 优化构造)

    Codeforces 题目传送门 & 洛谷题目传送门 本来说好的不做,结果今早又忍不住开了道题/qiao 我们称度为 \(1\) 的点为叶节点,度大于 \(1\) 的点为非叶节点. 首先考虑如 ...

  3. CF566E Restoring Map

    题意:乱序给你树上的每一个节点与之相距<=2的节点集合(并不知道这具体是哪个节点). 还原整棵树. 标程: #include<bits/stdc++.h> #define P pai ...

  4. WC2021 题目清单

    Day2 上午 <IOI题型与趣题分析> 来源 题目 完成情况 备注 IOI2002 Day1T1 Frog 已完成 IOI2002 Day1T2 Utopia IOI2002 Day1T ...

  5. Tree Restoring

    Tree Restoring Time limit : 2sec / Memory limit : 256MB Score : 700 points Problem Statement Aoki lo ...

  6. Backing Up and Restoring HBase Data

    There are two strategies for backing up HBase:1> Backing it up with a full cluster shutdown2> ...

  7. PatentTips – GPU Saving and Restoring Thread Group Operating State

    BACKGROUND OF THE INVENTION The present invention relates generally to single-instruction, multiple- ...

  8. mapreduce中一个map多个输入路径

    package duogemap; import java.io.IOException; import java.util.ArrayList; import java.util.List; imp ...

  9. .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法

    .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法 0x00 为什么需要Map(MapWhen)扩展 如果业务逻辑比较简单的话,一条主管道就够了,确实用不到 ...

随机推荐

  1. Windows10下打开MySQL服务 & 查看MySQL服务是否启动

    首先 确保电脑已安装MySQL客户端 其次 以管理员方式,打开Windows PowerShell 输入: net start mysql 回车 如下图: 可以了.

  2. 【MySQL】详细说下MySQL删除数据的过程是什么样的?

    drop table 这里先介绍一下[InnoDB]存储表空间概念: Innodb存储引擎,可将所有的数据库数据存放于[ibdata1]的共享表空间:也可以将每张表存放于独立的.idb文件的独立表空间 ...

  3. sobel( ) 算子

    只是简单的使用方面的记录 sobel()算子是图像处理中用于边缘检测的 opencv-python 中的函数形式为 def Sobel(src, ddepth, dx, dy, dst=None, k ...

  4. Mysql数值类型,小数点后保留两个零

    如有不足请帮忙留言区补充谢谢~ 一,数值类型保留小数点后两个0 在存入数据时,应客户需求数值类型,比如钱数,分数等等需要精确到小数点后几位. 800存入时显示为800.00 方法:在建表时直接定义此数 ...

  5. 第3章_关系数据库标准语言(SQL)_006_由元组关系演算到SQL Command_001_蕴含式 (其中有对EXISTS的分析)

    前序的链接:元组关系演算 六. 蕴含式 ===>1. 什么是“蕴含式”===>设p.q为两个命题.复合命题“如果p,则q”称为p与q的蕴含式,记作p→q,并称p为蕴含式的前件,q为后件.定 ...

  6. iOS开发图片选择

    一行代码搞定图片选择 // // gzhPhotoManager.h // 图片选择 // // Created by 郭志贺 on 2020/5/26. // Copyright © 2020 郭志 ...

  7. Java集合(八)哈希表及哈希函数的实现方式

    Java集合(八)哈希表及哈希函数的实现方式 一.哈希表 非哈希表的特点:关键字在表中的位置和它之间不存在一个确定的关系,查找的过程为给定值一次和各个关键字进行比较,查找的效率取决于和给定值进行比较的 ...

  8. Linux passwd 提权

    利用条件,passwd 可写 ls -al /etc/passwd 利用方式: 生成密钥  openssl passwd -1 -salt test 123456 写入passwd echo 'tes ...

  9. bypass disable_function的方法及蚁剑插件bypass-php-function使用

    bypass disable_function的方法及蚁剑插件bypass-php-function使用 在学习php时,发现有许多函数会对网站或系统造成很大危险隐患,常见的危险函数有: phpinf ...

  10. day 7 while循环

    #隐式布尔值: 0 none 空# 一.流程控制# 短路运算:偷懒原则,偷懒到哪个位置,就把当前位置的值返回# 为0# (10>3 and 10 and 0 and 10 )or( 10> ...