本文将同步发布于:

题目

题目链接:洛谷 P7025gym101612G

题意概述

给你一张有 \(n\) 个点 \(m\) 条边的无向图,无重边无自环,请你求出两个点 \(s,t\) 使得 \(s,t\) 之间有三条不重合的简单路径。

\(1\leq\sum n,\sum m\leq 10^5\)

题解

探究图的性质

考虑到本题是无向图,我们不难想到一个引理。

引理:无向图的 dfs 树上只存在树边和返祖边。

考虑到 dfs 树中只会存在树边、返祖边、横叉边,因此我们只需要证明无向图的 dfs 树上不存在横叉边即可。

考虑反证法。

假设存在一条横叉边 \((u,v)\),目前遍历到 \(u\),\(v\) 在之前被访问过,根据横叉边的定义,\(v\) 不是 \(u\) 的祖先。

根据深度优先搜索的深度优先原则,此时一定访问完了所有与 \(v\) 相连的节点,但 \(u\) 却未被访问到,造成矛盾,假设不成立,引理得证。

利用性质构造方案

考虑到 dfs 树上只有额外的返祖边,我们不难构造出一种方案。

对于一个点 \(u\),如果它的两棵子树内存在两个节点 \(x,y\) 使得有两条返祖边 \((x,p_1),(y,p_2)\) 满足 \(p_1,p_2\) 是节点 \(u\) 的祖先,则 \(s=p_1,t=u\) 符合条件。

画成图长下面这样:

充分性十分显然,下面我们考虑证明必要性。即不存在上述情况,也有满足条件的三条路径和两个节点。

不难发现这是不可能的,因为只要存在起点与终点,它们在 dfs 树上必然是祖先关系,因此一定满足上述情况,矛盾。

因此我们证明了这个条件的充分必要性,用 tarjan 算法判定即可。时间复杂度 \(\Theta(n)\)。

参考程序

#include<bits/stdc++.h>
using namespace std;
#define reg register
typedef long long ll;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
static char buf[1<<21],*p1=buf,*p2=buf;
#define flush() (fwrite(wbuf,1,wp1,stdout),wp1=0)
#define putchar(c) (wp1==wp2&&(flush(),0),wbuf[wp1++]=c)
static char wbuf[1<<21];int wp1;const int wp2=1<<21;
inline int read(void){
reg char ch=getchar();
reg int res=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))res=10*res+(ch^'0'),ch=getchar();
return res;
} inline void write(reg int x){
static char buf[32];
reg int p=-1;
if(x<0) x=-x,putchar('-');
if(!x) putchar('0');
else while(x) buf[++p]=(x%10)^'0',x/=10;
while(~p) putchar(buf[p--]);
return;
} const int MAXN=1e5+5; int n,m;
vector<int> G[MAXN];
int fa[MAXN];
int tim,dfn[MAXN],rnk[MAXN],low[MAXN],ed[MAXN],clow[MAXN],ced[MAXN];
int s,t; inline void tarjan(reg int u,reg int father){
fa[u]=father;
dfn[u]=low[u]=clow[u]=++tim;
rnk[tim]=u;
ed[u]=ced[u]=u;
for(int v:G[u])
if(v!=father){
if(!dfn[v]){
tarjan(v,u);
if(low[v]<low[u]){
clow[u]=low[u],ced[u]=ed[u];
low[u]=low[v],ed[u]=ed[v];
}
else if(low[v]<clow[u])
clow[u]=low[v],ced[u]=ed[v];
}
else{
if(dfn[v]<low[u]){
clow[u]=low[u],ced[u]=ed[u];
low[u]=dfn[v],ed[u]=u;
}
else if(dfn[v]<clow[u])
clow[u]=dfn[v],ced[u]=u;
}
}
if(!s&&!t&&clow[u]<dfn[u])
s=u,t=rnk[clow[u]];
return;
} inline vector<int> getPath(reg int son,int father){
vector<int> res;
for(int p=son;p!=father;p=fa[p])
res.push_back(p);
res.push_back(father);
return res;
} inline vector<int> reverse(vector<int> a){
reverse(a.begin(),a.end());
return a;
} inline vector<int> merge(vector<int> a,vector<int> b){
a.insert(a.end(),b.begin(),b.end());
return a;
} int main(void){
reg int T=read();
while(T--){
n=read(),m=read();
for(reg int i=1;i<=n;++i)
G[i].clear();
for(reg int i=1;i<=m;++i){
static int u,v;
u=read(),v=read();
G[u].push_back(v),G[v].push_back(u);
}
tim=0,fill(dfn+1,dfn+n+1,0);
s=0,t=0;
for(reg int i=1;i<=n;++i)
if(!dfn[i])
tarjan(i,0);
if(!s&&!t)
write(-1),putchar('\n');
else{
write(s),putchar(' '),write(t),putchar('\n');
vector<int> ans1=getPath(s,t);
write(ans1.size()),putchar(' ');
for(reg int i=0,siz=ans1.size();i<siz;++i)
write(ans1[i]),putchar(i==siz-1?'\n':' ');
vector<int> ans2=merge(reverse(getPath(ed[s],s)),reverse(getPath(t,rnk[low[s]])));
write(ans2.size()),putchar(' ');
for(reg int i=0,siz=ans2.size();i<siz;++i)
write(ans2[i]),putchar(i==siz-1?'\n':' ');
vector<int> ans3=merge(reverse(getPath(ced[s],s)),getPath(rnk[clow[s]],rnk[clow[s]]));
write(ans3.size()),putchar(' ');
for(reg int i=0,siz=ans3.size();i<siz;++i)
write(ans3[i]),putchar(i==siz-1?'\n':' ');
}
}
flush();
return 0;
}

「题解」NWRRC2017 Grand Test的更多相关文章

  1. 「题解」NWRRC2017 Joker

    本文将同步发布于: 洛谷博客: csdn: 博客园: 简书. 题目 题目链接:洛谷 P7028.gym101612J. 题意概述 有一个长度为 \(n\) 的数列,第 \(i\) 个元素的值为 \(a ...

  2. 「题解」「美团 CodeM 资格赛」跳格子

    目录 「题解」「美团 CodeM 资格赛」跳格子 题目描述 考场思路 思路分析及正解代码 「题解」「美团 CodeM 资格赛」跳格子 今天真的考自闭了... \(T1\) 花了 \(2h\) 都没有搞 ...

  3. 「题解」「HNOI2013」切糕

    文章目录 「题解」「HNOI2013」切糕 题目描述 思路分析及代码 题目分析 题解及代码 「题解」「HNOI2013」切糕 题目描述 点这里 思路分析及代码 题目分析 这道题的题目可以说得上是史上最 ...

  4. 「题解」JOIOI 王国

    「题解」JOIOI 王国 题目描述 考场思考 正解 题目描述 点这里 考场思考 因为时间不太够了,直接一上来就着手暴力.但是本人太菜,居然暴力爆 000 ,然后当场自闭- 一气之下,发现对 60pts ...

  5. 「题解」:[loj2763][JOI2013]现代豪宅

    问题 A: 现代豪宅 时间限制: 1 Sec  内存限制: 256 MB 题面 题目描述 (题目译自 $JOI 2013 Final T3$「現代的な屋敷」) 你在某个很大的豪宅里迷路了.这个豪宅由东 ...

  6. 「题解」:$Six$

    问题 A: Six 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 来写一篇正经的题解. 每一个数对于答案的贡献与数本身无关,只与它包含了哪几个质因数有关. 所以考虑二 ...

  7. 「题解」:$Smooth$

    问题 A: Smooth 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 维护一个队列,开15个指针,对应前15个素数. 对于每一次添加数字,暴扫15个指针,将指针对应 ...

  8. 「题解」:Kill

    问题 A: Kill 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 80%算法 赛时并没有想到正解,而是选择了另一种正确性较对的贪心验证. 对于每一个怪,我们定义它的 ...

  9. 「题解」:y

    问题 B: y 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 考虑双向搜索. 定义$cal_{i,j,k}$表示当前已经搜索状态中是否存在长度为i,终点为j,搜索过边 ...

随机推荐

  1. 【vue-07】vue-router

    Vue-router官网 安装 vue-router是一个插件包,所以我们还是需要用npm 来进行安装.打开命令行工具,进入你的项目目录,输入下面命令. npm install vue-router ...

  2. 1、requests基础

    一.升级pip版本的命令 : python -m pip install --upgrade pip 二.requests安装  windows系统系cmd运行 pip install request ...

  3. 从零开始搞监控系统(1)——SDK

    目前市面上有许多成熟的前端监控系统,但我们没有选择成品,而是自己动手研发.这里面包括多个原因: 填补H5日志的空白 节约公司费用支出 可灵活地根据业务自定义监控 回溯时间能更长久 反哺运营和产品,从而 ...

  4. 使用TK框架中selectByPrimaryKey

    使用TK框架中selectByPrimaryKey(Object key),需要注意要在entity里注明哪个字段是主键,否则会不知道哪个是PrimaryKey会随机一个字段就报错. 如下: 引入 i ...

  5. NetCore3.1及Vue开发通用RBAC前后端通用框架

    目录 框架说明 项目框架图 多租户权限设计表 效果图 后端拉取运行 前端项目请参考 前端系列 发布到docker中 netcore3.1 发布到docker中所遇到的坑及解决 框架说明 该框架是本人学 ...

  6. JavaScrip条件表达式优化

    目录 1,前言 2,多条件if语句优化 3,参数默认值 4,Switch语句优化 1,前言 今早看了一篇文章<JavaScrip实现:如何写出漂亮的条件表达式>,原创于:华为云开发者社区, ...

  7. [bug] Maven每次都自动下载jar包非常慢

    解决 方法一:将maven改为离线模式,自己下载jar包复制到仓库中 eclipse中Window>preferences>maven>勾选Offline 方法二:将maven镜像改 ...

  8. 查看报错原因 sshd -t

    b for ssh.service failed because the control process exited with error code. See "systemctl sta ...

  9. 使用find命令查找大文件

    使用find命令查找大文件 find命令是Linux系统管理员工具库中最强大的工具之一.它允许您根据不同的标准(包括文件大小)搜索文件和目录. 例如,如果在当前工作目录中要搜索大小超过100MB的文件 ...

  10. Python爬虫 小白[3天]入门笔记

    笔记来源 Day-0 1.如果你还不了解Python的基础语法,可以移步|>>>Python 基础 小白 [7天] 入门笔记<<<|或自行学习. 简介 1.什么是爬 ...