https://www.luogu.com.cn/problem/CF521E
题目大意
给你一个无向图,问图中是否存在两个点,连点之间至少有3条完全不相交的路径
输出三条路径
题解
一开始不太会做啊
还是要静下心来一步步画图推
首先肯定是先拉出一棵树,然后发现如果有一条边被覆盖了超过三次(LCA->D),那么就可以抽出三条路径
- LCA -> A -> C-> D
- LCA -> D
- LCA -> B -> D
具体实现可以暴力覆盖
因为每条边最多覆盖3次,所以是线性的
康康代码吧
code:
#include<bits/stdc++.h>
#define N 200050
using namespace std;
struct edge {
int v, nxt;
} e[N << 1];
int p[N], eid;
void init() {
memset(p, -1, sizeof p);
eid = 0;
}
void insert(int u, int v) {
e[eid].v = v;
e[eid].nxt = p[u];
p[u] = eid ++;
}
int dep[N], fa[N], ans[N], gs, hx[N], hy[N], vis[N], in[N], n, m;
int LCA(int x, int y) {
while(dep[x] > dep[y]) x = fa[x];
while(dep[x] < dep[y]) y = fa[y];
while(x != y) x = fa[x], y = fa[y];
return x;
}
void gett(int x, int y) {
while(x != y) {
ans[++ gs] = x;
x = fa[x];
}
ans[++ gs] = x;
}
void print() { printf("%d ", gs);
for(int i = 1; i <= gs; i ++) printf("%d ", ans[i]); printf("\n");
gs = 0;
}
void get(int a, int b, int c, int d) {
if(dep[b] > dep[d]) {
swap(b, d), swap(a, c);
}
int lca = LCA(a, c);
puts("YES");
gett(lca, d);
reverse(ans + 1, ans + 1 + gs);
print();
gett(d, b), gett(a, lca);
print();
ans[++ gs] = d; gett(c, lca);
print();
exit(0);
}
void dfs(int u) {
dep[u] = dep[fa[u]] + 1;
vis[u] = in[u] = 1;
for(int i = p[u]; i + 1; i = e[i].nxt) {
int v = e[i].v;
if(v == fa[u]) continue;
if(!vis[v]) {
fa[v] = u;
dfs(v);
} else if(in[v]) {
for(int x = u; x != v; x = fa[x]) {
if(hx[x] && hy[x]) get(hx[x], hy[x], u, v);
else {
hx[x] = u; hy[x] = v;
}
}
}
}
in[u] = 0;
}
int main() {
init();
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i ++) {
int u, v;
scanf("%d%d", &u, &v);
insert(u, v), insert(v, u);
}
for(int i = 1; i <= n; i ++) if(!vis[i]) dfs(i);
puts("NO");
return 0;
}
多画图
多思考