首页 > 其他分享 >「BalticOI 2011 Day2」Tree Mirroring 题解

「BalticOI 2011 Day2」Tree Mirroring 题解

时间:2023-07-09 19:12:27浏览次数:36  
标签:opt return fa 题解 ll Day2 Mirroring vis 节点

本文网址:https://www.cnblogs.com/zsc985246/p/17539182.html ,转载请注明出处。

题目大意

现在有一棵树 \(T\),复制一个完全相同的 \(T'\),并将这两棵树的叶子节点全部对应合并在一起,形成一个图,我们称这种图为对称图

给定一个图,判断它是否为对称图。

\(3 \le n,m \le 10^5\)

思路

我们称原树中的叶子节点组成对称轴

思考如果知道两棵树的根节点,能否找到对称轴上的所有点,进而判断是否为对称图。

发现一个点到两个根节点的距离相等当且仅当它在对称轴上

那么我们可以对两个根节点各做一次 bfs 计算距离来求出这些点。

在 bfs 时记录每个点在两个根节点的 bfs 树上的父亲,然后我们就可以从对称轴向两边的父亲拓展,每次将两个点匹配,如果发现重复匹配则不合法。

这样我们就可以通过两个根节点来进行 \(O(n)\) 判断合法性。

直接枚举根节点可以做到 \(O(n^3)\) 的复杂度,可以拿到 \(30\) 分。

判定过程无法优化,考虑优化枚举过程

发现如果有解,只要是对称的两个点都可以是根节点。

又因为对称轴上节点的度数一定为 \(2\),所以可以直接枚举这个度数为 \(2\) 的点,然后以相邻的两个点作为根节点判断。

这样就把复杂度优化到了 \(O(n^2)\),拿到 \(60\) 分。

如果想要继续优化,必须要有一种能保证找到一对对称点的 \(O(n)\) 方法。

考虑图中的环

首先把环长为 \(n\) 和没有环的情况判掉。

发现如果合法,那么任意一个环外点到环上一定有且仅有两条路径。

再进一步地,我们发现这两条路径的终点是一对对称点

那么就可以做到 \(O(n)\) 了。

需要注意的是,给定的是任意图,所以有可能两边是对称的图而不是树。

对于此,我们只需要记录对称轴上的点数 \(cnt\),然后判断 \(n+cnt-2\) 是否与 \(m\) 相等。

代码实现

#include<bits/stdc++.h>
#define ll long long
#define For(i,a,b) for(ll i=(a);i<=(b);++i)
#define Rep(i,a,b) for(ll i=(a);i>=(b);--i)
#define pb push_back
const ll N=1e6+10;
using namespace std;

ll n,m;
vector<ll>e[N];
ll in[N];

ll fa[2][N],dis[2][N];//记录两个根节点的bfs树上的父亲和距离
void chk(ll opt,ll s){//处理fa[opt]和dis[opt]
	For(i,1,n)fa[opt][i]=dis[opt][i]=-1;
	queue<ll>q;
	q.push(s);
	fa[opt][s]=dis[opt][s]=0;
	while(q.size()){
		ll x=q.front();
		q.pop();
		for(ll y:e[x]){
			if(~fa[opt][y])continue;
			q.push(y);
			dis[opt][y]=dis[opt][x]+1;
			fa[opt][y]=x;
		}
	}
}
ll match[N];//match[i]记录与i匹配的点
bool calc(ll x,ll y){//拓展匹配
	while(x&&y&&!match[x]&&!match[y]){
		match[x]=y,match[y]=x;//匹配
		x=fa[0][x],y=fa[1][y];//跳父亲
	}
	return match[x]==y&&match[y]==x;//是否重复匹配
}
bool check(ll s1,ll s2){//判断图是否合法,s1和s2为两个根节点
	chk(0,s1),chk(1,s2);
	ll ans=1,cnt=0;
	For(i,1,n){
		if(dis[0][i]==dis[1][i]){//距离相等
			ans&=calc(fa[0][i],fa[1][i]);//拓展匹配
			++cnt;//对称轴上点的个数
		}
	}
	return ans&&n+cnt-2==m;//判断对称的是树
}

ll top,s[N];//记录dfs经过的节点,方便找环
ll vis[N];//标记经过的点,特别地,环上的点vis为2
bool find(ll x,ll fat){//找环
	s[++top]=x;
	vis[x]=1;
	for(ll y:e[x]){
		if(y==fat)continue;
		if(vis[y]){
			do{vis[s[top]]=2;}while(s[top--]!=y);//标记环上的点
			return true;
		}
		if(find(y,x))return true;//找到就退出
	}
	return false;
}
bool bfs(ll sx){//找到sx到环的路径终点,sx是一个环外点
	vector<ll>t;//记录路径终点
	queue<ll>q;
	q.push(sx);
	vis[sx]=1;
	while(q.size()){
		ll x=q.front();
		q.pop();
		for(ll y:e[x]){
			if(vis[y]){
				if(vis[y]==2)t.pb(y);
				continue;
			}
			vis[y]=1;
			q.push(y);
		}
	}
	return t.size()==2&&check(t[0],t[1]);//合法时只有两条路径
}

int main(){
	
	scanf("%lld%lld",&n,&m);
	For(i,1,m){
		ll x,y;
		scanf("%lld%lld",&x,&y);
		e[x].pb(y),e[y].pb(x);
		++in[x],++in[y];
	}
	//有度数为1的点
	vector<ll>t;
	For(i,1,n)if(in[i]==1)t.pb(i);
	if(t.size()==2){//将这两个点作为根节点判断
		if(check(t[0],t[1]))printf("YES");
		else printf("NO");
		return 0;
	}
	if(t.size()){//合法时只可能有2个或0个度数为1的点
		printf("NO");
		return 0;
	}
	
	find(1,0);//找环
	For(i,1,n)if(vis[i]!=2)vis[i]=0;//清空
	For(i,1,n){
		if(!vis[i]){
			if(bfs(i))printf("YES");
			else printf("NO");
			return 0;
		}
	}
	//环长为n
	if(n&1)printf("NO");
	else printf("YES");
	
	return 0;
}

尾声

如果你发现了问题,你可以直接回复这篇题解

如果你有更好的想法,也可以直接回复!

标签:opt,return,fa,题解,ll,Day2,Mirroring,vis,节点
From: https://www.cnblogs.com/zsc985246/p/17539182.html

相关文章

  • P5175 题解
    题意简述给出数列\({a_n}(1\len\le10^{18})\)的两项\(a_1,a_2\)与递推公式\(a_n=xa_{n-1}+ya_{n-2}\),求:\[S_n=\sum_{k=1}^{n}a_k^2\mod(10^9+7)\]题目分析一看见\(1\len\le10^{18}\),就大概能知道要用\(O(\logn)\)级别的算法。再一看递推,就知道要用矩阵快速幂了。......
  • AT2402 题解
    题意简述给你\(n\)杯水,第\(i\)杯的水温为\(t_i\),容量为\(v_i\),依次倒入容量为\(V\)的大盆。注意每次倒入水后盆内水的总体积必须恒定为\(V\),且每杯水必须全部倒入,因此为防止倒进水时溢出,在倒水之前可以从盆里往外倒出一些水。求每次倒进水后盆里水温度的最大值(每次计算......
  • P4819 题解
    题意简述\(n\)个居民中有一名杀手,有些居民知道其他一些人的身份是杀手还是平民,该类条件共\(m\)条。现在警方要询问一些居民来获得其他人的信息,要求在能够从已知条件推断出杀手是谁的前提下询问尽可能少的人。然而每个居民是杀手的概率都是\(\frac{1}{n}\),因此警方询问的居民......
  • redis雪崩问题解决
    缓存雪崩出现的场景缓存服务器宕机,没有设置持久化介绍:缓存服务器宕机,没有设置持久化,导致缓存数据全部丢失,请求全部转发到数据库,造成数据库短时间内承受大量请求而崩掉。缓存集中失效缓存的key设置了相同的过期时间,导致在某一时刻,大量的key同时失效,请求全部转发到数据库,造成......
  • gym 102994M Travel Dream 题解
    给定带权无向图,求最大\(k\)元环。\(n,m\leq300,3\leqk\leq10\),无重边。把\(k=3\)判掉,可以\(O(m^2)\)轻松解决。把\(k\)元环拆成长度为\(\dfrac{k}{2}-1\)的链\(+\)长度\(k-\dfrac{k}{2}-1\)的链\(+\)连接两条链的两条边。(长度指边的个数)问题:两条链需要无......
  • 「NOIP 模拟赛 20230709」T3 - 与行星相会 题解
    题目大意原题有一个\(n\timesn\)的点阵,将相邻的点连边得到一个\((n-1)\times(n-1)\)的网格。\(q\)次操作,每次删掉一条边,求删掉后边两端的点是否仍在一个连通块内。强制在线。题解显然,由于对偶图的性质,原图的一个割对应对偶图中的一个环,所以只需要删掉一条边时在对偶图中......
  • 寻找页码题解
    首先看题目,我也不知道这一题的出处。。。。在网上找了很久也没找到。。。题目描述从第1页开始,页码组成的数字序列如下:123..101112..99100101...这串序列又被称之为连写数。给定一个0到9之中的单独一位数字a,请问在这串序列中,第k次出现a,是在哪一页上?以数码1为例,第......
  • 华泰证券FINTECH决赛第二题题解
    被第二题搞得坐牢2个半小时,在最后10分钟才确定推出的求和公式没问题,是除法取模不规范导致求解有偏差,只能说菜是原罪。这里贴一下赛后修改的代码,希望能对列位有些帮助,欢迎巨佬指导。思路:分奇偶讨论固定长度下伪回文串的数量,定义长度为\(n\)的伪回文串的数量为\(a_{n}\):(1)\(n\)......
  • P7112 题解
    题意简述模板题,求一个\(n\timesn(n\le600)\)的方阵的行列式模一个正整数\(p(1\lep\le10^9+7)\)的值(\(p\)不一定是质数)。题目分析这个题的最终代码其实很简单,重点在于过程。说实话,我在做这个题之前也就只知道个行列式的定义,只会暴力硬算。做了这个题才了解了行列式有那......
  • 关于Azure-平台-Redhat-Linux-服务器时间同步的问题解决
    首先说明一下,关于Azure平台中国区,是没有RedhatLinux系统镜像的于是笔者这边是通过在Windows系统 Hyper-V管理器中安装完Redhat8.x操作系统后,最后将系统磁盘转换成转换为VHD格式然后经过一系列操作、最终在Azure平台上形成了自己的并且加固过的RedHatEnterpriseLinuxre......