【Codeforces 521E】Cycling City
构造?
题目大意:
给定一张简单无向图,要求找到两个点 $u,v$,使得 $u$ 和 $v$ 之间存在三条不经过重复点(除了起点和终点外)的路径。输出方案或判断无解。
题解:
考虑先对原图进行 dfs 遍历,求出生成树。那么剩下的边一定都是返祖边。
我们令一条返祖边跨过的点称为被它包含的点。考虑两条返祖边,若被它们同时包含的点存在至少 $2$ 个,则我们找到一条方案。两个端点为同时包含的点的最深、最浅的点。
这个最深的点,就是两条返祖边较深一端的 LCA,而最浅的点,就是两条返祖边较浅一端中,深度较大的那个点。
所以输出方案也很好弄了。
Code:
#include<cstdio>
#include<cstdlib>
#include<vector>
const int N=2e5+6;
struct edge{
int to,nxt;
bool vis;
}e[N<<1];
int head[N],cnt=1,n,m,dep[N],fa[N],up[N];
bool vis[N];
std::vector<int>out;
void O_R(int now,const int&ed){
if(now!=ed)O_R(fa[now],ed);
out.push_back(now);
}
void output(){
printf("%d",out.size());
for(int i=0;i<out.size();++i)printf(" %d",out[i]);
putchar('\n');
out.clear();
}
void DFS(int now,int pre){
vis[now]=1;
for(int i=head[now];i;i=e[i].nxt)
if(i!=pre&&!vis[e[i].to]){
e[i].vis=1;
dep[e[i].to]=dep[now]+1;
fa[e[i].to]=now;
DFS(e[i].to,i^1);
}else
if(dep[e[i].to]<dep[now]&&i!=pre){
if(!up[now])up[now]=e[i].to;
else{
puts("YES");
int u=up[now],v=e[i].to;
if(dep[u]<dep[v])u^=v^=u^=v;
out.push_back(now);
for(int s=now;s!=u;s=fa[s])out.push_back(fa[s]);
output();
printf("2 %d %d\n",now,u);
out.push_back(now);
O_R(u,v);
output();
exit(0);
}
}
}
int dfs(int now){
int res=up[now]?now:0;
for(int i=head[now];i;i=e[i].nxt)
if(e[i].vis){
int t=dfs(e[i].to);
if(up[t]==now)t=0;
if(res&&t){
int u=up[res],v=up[t];
if(dep[u]<dep[v])u^=v^=u^=v,res^=t^=res^=t;
puts("YES");
O_R(res,now),out.push_back(u);
output();
out.push_back(now);
for(int s=now;s!=u;s=fa[s])out.push_back(fa[s]);
output();
O_R(t,now),O_R(u,v);
output();
exit(0);
}else if(t)res=t;
}
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i){
int u,v;
scanf("%d%d",&u,&v);
e[++cnt]=(edge){v,head[u]},head[u]=cnt;
e[++cnt]=(edge){u,head[v]},head[v]=cnt;
}
for(int i=1;i<=n;++i)if(!dep[i])dep[i]=1,DFS(i,0);
for(int i=1;i<=n;++i)if(dep[i]==1)dfs(i);
puts("NO");
return 0;
}