码迷,mamicode.com
首页 > 其他好文 > 详细

【CF566E】Restoring Map(构造)

时间:2021-04-01 13:20:09      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:using   多个   its   pen   inline   problem   集中   type   const   

点此看题面

  • 有一棵\(n\)个点的树,乱序给出与每个点距离小于等于\(2\)的点集。
  • 求构造一棵合法的树。
  • \(n\le10^3\)

非叶节点间的连边

两个非叶节点\(x,y\)之间存在边,则对于它们两侧的两点\(i,j\),同时与\(i,j\)距离小于等于\(2\)的点只有\(x,y\)两点。

因此,非叶节点\(x,y\)之间有边的充要条件就是存在两个点集的交集恰好是\(\{x,y\}\)。要求这个,只需用枚举一对点集用\(bitset\)优化即可。

叶节点的连边

对于叶节点,显然它对应的点集是所有包含它的点集中最小的那个(可能有多个最小的,是和它同父节点的兄弟们,肯定都一样)。

而要找它的父节点,则它点集中所有的非叶节点应该恰好是它父节点的连边集合(加上父节点本身)。因此只要找到一个点的连边集合和修改后的点集相同,这个点就是它的父节点。

非叶节点很少时的判断

首先,如果没有非叶节点,则\(n=2\),直接判断即可。

其次,如果非叶节点数量为\(1\),那么这是一张菊花图,所有点的点集都是\(1\sim n\),很容易判断出来,然后只要随便找个点做菊花图的中心即可。

再次,如果非叶节点数量为\(2\),先按照之前的方法求出这两个叶节点,那么点集可以被划分成两部分,随便分给这两个点即可。

代码:\(O(\frac{n^3}{32})\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000
using namespace std;
int n,p[N+5],w[N+5][N+5];bitset<N+5> s,S[N+5],E[N+5];
namespace FastIO
{
	#define FS 100000
	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
	Tp I void write(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);}
	Tp I void writeln(Con Ty& x,Con Ty& y) {write(x),pc(‘ ‘),write(y),pc(‘\n‘);}
}using namespace FastIO;
int main()
{
	#define Exit return clear(),0
	RI i,j,x,y;for(read(n),i=1;i<=n;++i) for(read(x);x;--x) read(y),S[i].set(y);if(n==2) {writeln(1,n);Exit;}//特判无叶节点
	for(i=1;i<=n;++i) {for(j=1;j<=n&&S[i].test(j);++j);if(j<=n) break;}if(i>n) {for(i=2;i<=n;++i) writeln(1,i);Exit;}//特判一个叶节点
	RI t=0;for(i=1;i<=n;++i) for(j=i+1;j<=n;++j) (s=S[i]&S[j]).count()==2&&(x=s._Find_first(),//枚举每对点集求交
		y=s._Find_next(x),!w[x][y]&&(writeln(x,y),E[x].set(y),E[y].set(x),p[x]=p[y]=w[x][y]=w[y][x]=1,++t));//一对非叶节点间的连边
	if(t==1) {for(i=1;i<=n&&S[i].count()==n;++i);for(j=1;j<=n;++j) !p[j]&&(writeln(S[i].test(j)?x:y,j),0);Exit;}//特判两个叶节点
	for(i=1;i<=n;++i) p[i]&&(E[i].set(i),0);for(i=1;i<=n;++i) if(!p[i])//枚举每个非叶节点找父节点
	{
		for(t=0,j=1;j<=n;++j) S[j].test(i)&&(!t||S[j].count()<S[t].count())&&(t=j);//找所在最小点集
		for(s.reset(),j=1;j<=n;++j) S[t].test(j)&&p[j]&&(s.set(j),0);for(j=1;j<=n;++j) if(E[j]==s) {writeln(i,j);break;}//删去叶节点找父节点
	}return clear(),0;
}

【CF566E】Restoring Map(构造)

标签:using   多个   its   pen   inline   problem   集中   type   const   

原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF566E.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!