本文将同步发布于:

题目

题目链接:洛谷 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. CVE-2010-3974:Windows 传真封面编辑器 FxsCover.exe 双重释放漏洞调试分析

    0x01 堆空间申请后的双重释放 Windows FxsCover 程序存储封面编辑器的信息,封面编辑器是传真服务的一个组件,通过解析特定的传真封面文件(.cov)时,会调用类析构函数对同一内存中的栈 ...

  2. Windows核心编程 第27章 硬件输入模型和局部输入状态

    第27章 硬件输入模型和局部输入状态 这章说的是按键和鼠标事件是如何进入系统并发送给适当的窗口过程的.微软设计输入模型的一个主要目标就是为了保证一个线程的动作不要对其他线程的动作产生不好的影响. 27 ...

  3. 【python】【补】Leetcode每日一题-合并两个有序数组

    [python]Leetcode每日一题-合并两个有序数组 [题目描述] 给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组 ...

  4. (数据科学学习手札121)Python+Dash快速web应用开发——项目结构篇

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...

  5. 从0开始fastjson漏洞分析

    关于fastjson漏洞利用参考:https://www.cnblogs.com/piaomiaohongchen/p/10799466.html fastjson这个漏洞出来了很久,一直没时间分析, ...

  6. Codeforces Round #687 (Div. 2, based on Technocup 2021 Elimination Round 2)

    A. Prison Break 题意:就是在一个n*m的矩阵中,以(1,1)为起点(n,m)为终点,每个点以每个单位1s的速度移动,问总共至少需要多少秒,所有的矩阵点就能够全部移动到(r,c)中 思路 ...

  7. sosreport命令 然后diff 正常的操作系统例如centos

    nux学习笔记:有用的linux命令  发表于 2018-06-25 |  分类于 linux|  字数统计: 1,269 |  阅读时长 ≈ 6 写在前面 这着笔记,整理一些网上搜集到有用的linu ...

  8. useradd linux系统创建用户和设置密码简单脚本-1

    useradd linux系统创建用户和设置密码简单脚本-1 linux_wangqiang 2019-12-04 20:51:18 65 收藏展开#!/bin/bash#快速创建用户 使用$1第一个 ...

  9. FireFox-background

  10. BLDC 无刷电机FOC驱动 STM32官方培训资料

    STM32 PMSM FOC SDK V3.2 培训讲座一http://v.youku.com/v_show/id_XNTM2NjgxMjU2.html?from=s1.8-1-1.2STM32 PM ...