本文将同步发布于:

题目

题目链接:洛谷 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. Linux中su、sudo、sudo -i的用法和区别

    sudo :暂时切换到超级用户模式以执行超级用户权限,提示输入密码时该密码为当前用户的密码,而不是超级账户的密码.缺点是每次执行超级用户权限都要在命令前加上 sudo ,优点是在当前终端再使用 sud ...

  2. (3) arm 指令

    跳转指令1.1 B 跳转指令 B{cond} label 说明:如果条件cond满足,arm处理器将立即跳转到label指定的地址处继续执行.1.2 BL 带链接的跳转指令 BL{cond} labe ...

  3. shell中的引号和转义

    引号和转义 Bash 只有一种数据类型,就是字符串.不管用户输入什么数据,Bash 都视为字符串.因此,字符串相关的引号和转义,对 Bash 来说就非常重要. 转义 某些字符在 Bash 里面有特殊含 ...

  4. Day009 冒泡排序

    冒泡排序 冒泡排序无疑是最为出名的排序算法之一,总共有八大排序! 冒泡排序的代码还是相当简单的,两层循环,外层冒泡轮数,里层依次比较,江湖中人人尽皆知. 我们看到嵌套循环,应该立马就可以得出这个算法的 ...

  5. Java GUI入门手册-AWT篇

    Java GUI入门手册: AWT是基本的GUI设计工具,重点学习其中的布局格式以及事件监听事件. 首先创建一个窗口,我们先分析Frame类中的方法: 通过上图,可以看出frame是由构造方法的重载: ...

  6. 【死磕JVM】用Arthas排查JVM内存 真爽!我从小用到大

    Arthas是啥 当我们系统遇到JVM或者内存溢出等问题的时候,如何对我们的程序进行有效的监控和排查,就发现了几个比较常用的工具,比如JDK自带的 jconsole.jvisualvm还有一个最好用的 ...

  7. c++通讯录管理系统

    代码拷贝 #include<iostream> #include<string> #include<stdlib.h> #define MAX 1000 using ...

  8. 初识Vue2(一):表单输入绑定(附Demo)

    在线演示 http://demo.xiongze.net/ 下载地址 https://gitee.com/xiongze/Vue2.git js引用 <!--这里可以自己下载下来引用,也可以使用 ...

  9. spring总结归纳

    愿历尽千帆,归来仍是少年 简介 spring: 1.是分层的full-stack(全栈)轻量级开源框架.2. 内核:IOC和AOP.3.提供web层springMvc和业务层事务管理,整合众多的开源框 ...

  10. Spring Cloud 升级之路 - 2020.0.x - 5. 理解 NamedContextFactory

    spring-cloud-commons 中参考了 spring-cloud-netflix 的设计,引入了 NamedContextFactory 机制,一般用于对于不同微服务的客户端模块使用不同的 ...