圆方树

longdie

2020-09-17 17:51:06

Personal

# 圆方树 ## 学习链接 : [圆方树](https://www.cnblogs.com/PinkRabbit/p/10446473.html) ## 易错点 1. 理解概念, 圆方树是把每个点双新建成了方点,原来的点是圆点。 2. 理解判定条件 `low[v] == dfn[u]` 3. 注意公共点不出栈 4. 注意每次tarjan后把栈顶减去。 ``` cpp int n, m, cnt, fa[N<<1], ans[N], tot; vector<int> g[N<<1], t[N<<1]; int dfn[N], low[N], dfs_clock, sta[N], top; void tarjan(int u) { low[u] = dfn[u] = ++dfs_clock; sta[++top] = u; for(register int i = 0; i < g[u].size(); ++i) { int v = g[u][i]; if(!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); if(low[v] == dfn[u]) { ++cnt; for(int x = 0; x != v; --top) { x = sta[top]; t[cnt].push_back(x); t[x].push_back(cnt); } t[cnt].push_back(u); t[u].push_back(cnt); } } else low[u] = min(low[u], dfn[v]); } } ``` ## 学习心得 * 方点直接在原来的基础上建即可。 * 一定要注意千万不要把割点出栈。 下面给份代码 : ``` cpp #include <bits/stdc++.h> using namespace std; const int N = 1e5 + 5, M = 1e6 + 5; int n, m; struct edge { int to, next, w; } e[M]; int head[N], cnt; void add(int x, int y, int z) { e[++cnt].to = y, e[cnt].next = head[x], e[cnt].w = z, head[x] = cnt; } int dfn[N], low[N], dfs_clock, sta[N], top; void tarjan(int u) { dfn[u] = low[u] = ++dfs_clock, sta[++top] = u; for(int i = head[u]; i; i = e[i].next) { int v = e[i].to; if(!dfn[v]) { tarjan(v), low[u] = min(low[u], low[v]); if(low[v] == dfn[u]) { ++n; int x = sta[top]; while(x != u) { add(x, n, 0), add(n, x, 0); x = sta[--top]; } add(u, n, 0), add(n, u, 0);// 别忘了加点 } } else low[u] = min(low[u], dfn[v]); } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); cin >> n >> m; for(int i = 1; i <= m; ++i) { int x, y, z; cin >> x >> y >> z; add(x, y, z), add(y, x, z); } for(int i = 1; i <= n; ++i) if(dfn[i]) tarjan(i); return 0; } ``` ## 圆方树的应用 已经学完了知识,该来道例题了。 #### 题目链接 : [[ZJOI2004]嗅探器](https://www.luogu.com.cn/problem/P5058) #### 题解链接 : [嗅探器](https://www.luogu.com.cn/blog/nitubenben/p5058-zjoi2004-xiu-tan-qi-yuan-fang-shu-ti-xie#) 这篇题解已经讲的很清晰了,不过还有几个注重点,首先需要思考什么时候可以取答案,为什么可以这样就是对的,而不是一味平感觉,只看结论。 下面奉上我自己觉的很好的码风,~~既不那么压行,有简单易懂。~~ ``` cpp #include <bits/stdc++.h> using namespace std; const int N = 4e5 + 5, M = 2e6 + 5; int n, nn; int head[N], cnt; int start, target; struct edge { int to, next; } e[M]; void add(int x, int y) { e[++cnt].to = y, e[cnt].next = head[x], head[x] = cnt; } int dfn[N], low[N], sta[N], top, dfs_clock; vector<int> g[N]; void tarjan(int u) { dfn[u] = low[u] = ++dfs_clock, sta[++top] = u; for(int i = head[u]; i; i = e[i].next) { int v = e[i].to; if(!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); if(low[v] == dfn[u]) { nn++; while(1) { int x = sta[top--]; g[x].push_back(nn), g[nn].push_back(x); if(x == v) break; } g[u].push_back(nn), g[nn].push_back(u); } } else low[u] = min(low[u], dfn[v]); } } void dfs(int u, int fa, int ans) { if(u == target) { if(ans == 0) cout << "No solution"; else cout << ans; exit(0); } if(u != start && u <= n && g[u].size() > 1) ans = ans == 0 ? u : min(ans, u); for(int i = 0; i < g[u].size(); ++i) { int v = g[u][i]; if(v == fa) continue; dfs(v, u, ans); } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); cin >> n; int x, y; nn = n; while(cin >> x >> y && x != 0 && y != 0) add(x, y), add(y, x); cin >> start >> target; tarjan(start); if(dfn[target] == 0) return cout << "No solution", 0; dfs(start, 0, 0); return 0; } ```