@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@

#include <bitset>
#include <cstdio>
#include <algorithm>
using namespace std; int tag[1005], n;
bitset<1005>a[1005], b[1005], c[1005], t, p;
int main() {
scanf("%d", &n);
for(int i=1;i<=n;i++) {
int k, x; scanf("%d", &k);
for(int j=1;j<=k;j++)
scanf("%d", &x), b[i][x] = 1;
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++) {
t = (b[i] & b[j]);
// printf("%d %d : %d\n", i, j, t.count());
if( t.count() == 2 ) {
int x = t._Find_first(); t[x] = 0;
int y = t._Find_first();
a[x][y] = a[y][x] = 1;
}
}
t = 0;
for(int i=1;i<=n;i++)
if( a[i].count() ) tag[i] = -1, t[i] = 1;
for(int i=1;i<=n;i++) a[i][i] = 1;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if( a[i][j] ) printf("%d %d\n", i, j);
if( t.count() == 0 ) {
for(int i=2;i<=n;i++)
printf("%d %d\n", 1, i);
}
else if( t.count() == 2 ) {
for(int x=1;x<=n;x++) {
for(int y=x+1;y<=n;y++) {
if( a[x][y] ) {
bool flag = false;
for(int i=1;i<=n;i++)
if( b[i].count() != n ) {
for(int j=1;j<=n;j++)
if( b[i][j] ) {
if( tag[j] == 1 ) break;
else if( tag[j] != -1 ) {
printf("%d %d\n", flag ? y : x, j);
tag[j] = 1;
}
}
flag = true;
}
}
}
}
}
else {
for(int i=1;i<=n;i++) {
c[i] = (b[i] & t);
bool flag = true;
for(int j=1;j<=n;j++)
if( b[i] == b[j] ) {
if( j < i ) {
flag = false;
break;
}
}
else if( (b[i] & b[j]) == b[j] ) {
flag = false;
break;
}
if( flag ) {
for(int j=1;j<=n;j++)
if( c[i] == a[j] ) {
for(int k=1;k<=n;k++)
if( b[i][k] && tag[k] == 0 )
printf("%d %d\n", j, k), tag[k] = 1;
break;
}
}
}
}
}

@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. Chipmunk-js物理引擎学习笔记

    一.基本概念## 空间:在Chipmunk中,空间是所有对象容器.因此,刚体.形状.链接节点等对象都需要添加到空间中.空间控制这些对象的相互作用. 刚体:物理上的刚体指的是在运动和受力作用后,形状和大 ...

  2. 仙人掌图判定及求直径HDU3594 BZOJ1023

    https://wenku.baidu.com/view/ce296043192e45361066f575.html   //仙人掌图基础知识3个判定条件 http://blog.csdn.net/y ...

  3. CF832C

    题目链接:http://codeforces.com/contest/832/problem/C 题目大意: n个人,面向左或者右站在同一条轴上,每个人在轴上的坐标为x,速度为v.请你在某个位置放置一 ...

  4. SpringBoot2.1电商通用(微信+支付宝)支付系统实战

    『课程目录』: ├─第10章 全模块电商系统之商品模块 │      10-1_商品列表-上.mp4 │      10-2_商品列表-中.mp4 │      10-3_商品列表-下.mp4 │  ...

  5. Python_OpenCV学习记录01安装

    Python照样快! 众所周知,虽然Python语法简洁,编写高效,但相比C/C++运行慢很多.然 而Python还有个重要的特性:它是一门胶水语言!Python可以很容易地扩展 C/C++.Open ...

  6. 一文讲透Modbus协议

    前言 Modbus是一种串行通讯协议,是Modicon公司(现在的施耐德电气 Schneider Electric) 于1979年为使用可编程逻辑控制器(PLC)通信而发表.Modbus已经成为工业领 ...

  7. PHP常量的定义和用法

    我们通常把不经常变的值定义成常量,常量一般用全部大写来表示,前面不加美元符号,也可减少团队开发的出错.那么define和const有什么区别呢? 1.const是一个语言结构:而define是一个函数 ...

  8. [nginx报错问题]reload时报错:nginx: [error] invalid PID number "" in ...

    错误 第一次探索nginx,执行以下命令时: nginx -s reload 报出错误: nginx: [error] invalid PID number "" in ... * ...

  9. 【Gabor】基于多尺度多方向Gabor融合+分块直方图的表情识别

    Topic:表情识别Env: win10 + Pycharm2018 + Python3.6.8Date:   2019/6/23~25 by hw_Chen2018                  ...

  10. [工具推荐]001.FlipPDF使用教程

    FlipPDF是一个什么样的软件呢,他有什么实际用途呢?顾名思义,这是一个跟PDF有关的软件,没错它是一款把PDF转换成酷炫书籍的软件,他还支持PDF中的目录,也就是转换成的书籍,目录一样可以跳转的. ...