题解 [CF521E] Cycling City
发现就是找一个环,要求环上有一根弦
直接找不好找,把 dfs 树建出来
然后发现只要有一条边同时被至少两个环包含就一定有解
但输出方案比较麻烦
要是在赛时我就写个拍然后大力分类讨论
艹正解就是分类讨论
但是……
- 脑残时可能会忘记:dfs 树是没有横叉边的!
但是这并不意味着扫出边时已经访问过的点都是祖先,横叉边在此时同样会被扫描到
然后只有返祖边的话只有三种情况
一个方便的写法是求两个下端点的 lca 和两个上端点中较浅者
这样三种情况可以合成一种来写
复杂度 \(O(n\log n)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m;
bool intr[N], vis[N];
int head[N], sta[N], lg[N], fa[21][N], dep[N], val[N], from[N], to[N], tem[N], ecnt=1, top, top2;
struct edge{int to, next;}e[N<<1];
inline void add(int s, int t) {e[++ecnt]={t, head[s]}; head[s]=ecnt;}
int lca(int a, int b) {
if (dep[a]<dep[b]) swap(a, b);
while (dep[a]>dep[b]) a=fa[lg[dep[a]-dep[b]]-1][a];
if (a==b) return a;
for (int i=lg[dep[a]]-1; ~i; --i)
if (fa[i][a]!=fa[i][b])
a=fa[i][a], b=fa[i][b];
return fa[0][a];
}
void split(int u, int v) {assert(dep[u]>=dep[v]); for (top=0; ; u=fa[0][u]) if ((sta[++top]=u)==v) return ;}
void print(int down1, int up1, int down2, int up2) {
// cout<<down2<<' '<<up2<<endl;
puts("YES");
assert(dep[down1]>dep[up1] && dep[down2]>dep[up2]);
int up=dep[up1]>dep[up2]?up1:up2;
if (dep[up1]>dep[up2]) swap(up1, up2), swap(down1, down2);
int down=lca(down1, down2);
// cout<<"up&down: "<<up<<' '<<down<<endl;
split(down, up);
printf("%d ", top); for (int j=1; j<=top; ++j) printf("%d%c", sta[j], " \n"[j==top]);
split(down1, down); reverse(sta+1, sta+top+1);
for (int j=1; j<=top; ++j) tem[++top2]=sta[j];
split(up, up1); reverse(sta+1, sta+top+1);
for (int j=1; j<=top; ++j) tem[++top2]=sta[j];
printf("%d ", top2); for (int j=1; j<=top2; ++j) printf("%d%c", tem[j], " \n"[j==top2]);
split(down2, down); reverse(sta+1, sta+top+1);
sta[++top]=up;
printf("%d ", top); for (int j=1; j<=top; ++j) printf("%d%c", sta[j], " \n"[j==top]);
exit(0);
}
void dfs(int u, int pa) {
vis[u]=1;
for (int i=1; i<21; ++i)
if (dep[u]>=1<<i) fa[i][u]=fa[i-1][fa[i-1][u]];
else break;
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (v==pa) continue;
if (vis[v]) {
if (dep[v]>=dep[u]) continue;
if (val[u]) print(u, v, from[u], to[u]);
else {val[u]=1, from[u]=u, to[u]=v; continue;}
}
fa[0][v]=u;
dep[v]=dep[u]+1;
dfs(v, u);
if (val[v] && u!=to[v]) {
if (val[u]) print(from[u], to[u], from[v], to[v]);
else val[u]=1, from[u]=from[v], to[u]=to[v];
}
}
}
signed main()
{
n=read(); m=read();
memset(head, -1, sizeof(head));
for (int i=1,u,v; i<=m; ++i) {
u=read(); v=read();
add(u, v); add(v, u);
}
for (int i=1; i<=n; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
for (int i=1; i<=n; ++i) if (!vis[i]) dep[i]=1, dfs(i, 0);
puts("NO");
return 0;
}