ZOJ 4097 Rescue the Princess 边双缩点+LCA
给你一个图和三个点U,V,W 问你是否存在从U到V和从U到W的两条边不相交路径
先边双缩点 再每个连通分量搞LCA 最后LCA判
![](/assets/blank.gif)
![](/assets/blank.gif)
#include<bits/stdc++.h> using namespace std; #define INF 0xfffffff #define maxn 200025 #define min(a,b) (a<b?a:b) int m, n, Time, cnt, top; int dfn[maxn], block[maxn], low[maxn], Father[maxn], Stack[maxn]; int Bcc[maxn], Bcccnt = 0; vector<int> G[maxn], G2[maxn]; inline void read(int &v) {v = 0;char c = 0;int p = 1;while (c < '0' || c > '9') {if (c == '-') {p = -1;}c = getchar();}while (c >= '0' && c <= '9') {v = (v << 3) + (v << 1) + c - '0';c = getchar();}v *= p; } void Tarjan(int u, int fa) {dfn[u] = low[u] = ++Time;Father[u] = fa;Stack[top++] = u;int len = G[u].size(), v, k = 0;for (int i = 0; i < len; i++) {v = G[u][i];if (v == fa && !k) {k ++;continue;}if (!low[v]) {Tarjan(v, u);low[u] = min(low[u], low[v]);} else {low[u] = min(low[u], dfn[v]);}}if (dfn[u] == low[u]) {do {v = Stack[--top];block[v] = cnt;} while (u != v);cnt ++;} } void getBcc(int x, int y) {Bcc[x] = y;for (auto v : G[x]) {if (Bcc[v] == 0) {getBcc(v, y);}} } int T; int q, N; int u, v, c, w;typedef struct {int from, to, w; } edge; //这个结构体用来存储边 vector<edge> edges; //保存边的数组 int grand[maxn][20]; //x向上跳2^i次方的节点,x到他上面祖先2^i次方的距离 int depth[maxn];//深度 int root; bool vis[maxn]; void addedge(int x, int y, int w) { //把边保存起来的函数edge a = {x, y, w}, b = {y, x, w};edges.push_back(a);edges.push_back(b);G2[x].push_back(edges.size() - 2);G2[y].push_back(edges.size() - 1); } void dfs(int x) { //dfs建图vis[x] = 1;for (int i = 1; i <= N; i++) { //第一个几点就全部都是0,第二个节点就有变化了,不理解的话建议复制代码输出下这些数组grand[x][i] = grand[grand[x][i - 1]][i - 1]; //倍增 2^i=2^(i-1)+2^(i-1) }for (int i = 0; i < G2[x].size(); i++) {edge e = edges[G2[x][i]];if (e.to != grand[x][0]) { //这里我们保存的是双向边所以与他相连的边不是他父亲就是他儿子父亲的话就不能执行,不然就死循环了。depth[e.to] = depth[x] + 1; //他儿子的深度等于他爸爸的加1grand[e.to][0] = x; //与x相连那个节点的父亲等于x//gwmax[e.to][0]=e.w;dfs(e.to);//深搜往下面建 }} } int lca(int a, int b) {if (a == b) {return a;}if (depth[a] > depth[b]) {swap(a, b); //保证a在b上面,便于计算 }for (int i = N; i >= 0; i--) { //类似于二进制拆分,从大到小尝试if (depth[a] < depth[b] && depth[grand[b][i]] >= depth[a]) { //a在b下面且b向上跳后不会到a上面b = grand[b][i]; //先把深度较大的b往上跳 }}if (a == b) {return a;}for (int j = N; j >= 0; j--) { //在同一高度了,他们一起向上跳,跳他们不相同节点,当全都跳完之后grand【a】【0】就是lca,上面有解释哈。if (grand[a][j] != grand[b][j]) {a = grand[a][j];b = grand[b][j];}}if (grand[a][0] == 0 && grand[b][0] == 0 && a != b) {return -1;}return grand[a][0]; }void init(int n) {edges.clear();Bcccnt = cnt = 1;top = Time = 0;for (int i = 0; i <= n; i++) {vis[i] = dfn[i] = low[i] = block[i] = Father[i] = Bcc[i] = 0;G[i].clear();G2[i].clear();} } int main() {read(T);while (T--) {read(n), read(m), read(q);init(n + 1);for (int i = 1; i <= m; i++) {read(u), read(v);if (u != v) {G[u].push_back(v);G[v].push_back(u);}}for (int i = 1; i <= n; i++) {if (Bcc[i] == 0) {getBcc(i, Bcccnt);Bcccnt++;}}for (int i = 1; i <= n; i++) {if (!low[i]) {Tarjan(i, i);}}depth[0] = -1;N = floor(log(cnt + 0.0) / log(2.0)) + 1; //最多能跳的2^i祖先for (int i = 1; i <= n; i++) {v = Father[i];if (block[i] != block[v]) {addedge(block[i], block[v], 1);}}for (int i = 1; i < cnt; i++) {if (!vis[i]) {depth[i] = 0;root = i;dfs(root);}}for (int i = 1; i <= q; i++) {read(u), read(v), read(w);if (Bcc[u] != Bcc[v] || Bcc[u] != Bcc[w]) {printf("No\n");continue;}u = block[u], v = block[v], w = block[w];if (u == v || u == w) {printf("Yes\n");continue;}if (v == w) {printf("No\n");continue;}int t[] = {u, lca(u, w), lca(u, v), lca(v, w)};sort(t, t + 4, [](int x, int y) {return depth[x] < depth[y];});if (t[2] == u && t[3] == u) {printf("Yes\n");} else {printf("No\n");}}}return 0; }
View Code
转载于:https://www.cnblogs.com/Aragaki/p/10712568.html
ZOJ 4097 Rescue the Princess 边双缩点+LCA相关推荐
- POJ - 3694 Network(边双缩点+LCA+并查集优化)
题目链接:点击查看 题目大意:给出一个由n个点组成的无向图,现在有m次操作,每次操作都会向图中增加一条无向边,每次操作后询问当前图中有多少个桥 题目分析:题意很好理解,思路也很好想,就是代码量有点小多 ...
- 中石油训练赛 - Plan B(点双缩点+树形dp)
题目大意:给出一张 n 个点 m 条边的无向连通图,现在有某些点被标记了,问能否通过删除某个未被标记的点,使得删除该点后的数个互不相交的连通块中,至少存在一个联通块中不含有被标记的点 题目分析:首先不 ...
- 中石油训练赛 - One-Way Conveyors(边双缩点+树上差分)
题目链接:点击查看 题目大意:给出一张 n 个点 m 条边的无向图,现在需要将这张图转换为有向图,并且使得 k 个可达条件成立,输出一种构造方案 题目分析:如果在无向图中出现环的话,那么在转换为有向图 ...
- CodeForces - 1220E Tourism(边双缩点+树形dp)
题目链接:点击查看 题目大意:给出一个由n个点和m条边构成的无向图,每个点都有一个权值,现在给出起点st,问从起点出发,如何规划路线可以使得途径的权值最大,唯一的约束是一条边不能连续经过,比如当前从u ...
- HDU - 4612 Warm up(边双缩点+树的直径)
题目链接:点击查看 题目大意:给出一个由n个点和m条边构成的无向图,现在允许加一条边,使得整张图中桥的数量最少,求最少的桥的数量 题目分析:因为是要求桥,所以直接用tarjan边双缩点,将原图转换成一 ...
- POJ - 3177 Redundant Paths(边双缩点)
题目链接:点击查看 题目大意:给出一个由n个点和m条边构成的无向图,现在问至少添加几条边,才能使得任意两点之间都能由至少两条不同的路到达 题目分析:既然要让任意两点之间至少由两条道路连接,换句话说也就 ...
- 无向图缩点:tarjan点双与边双缩点(模板)
e-DCC边双缩点:(用之前记得init) cnt1是从2开始的 边双缩点可以将无向图转换为一个森林,如果原图保证连通的话,那么可以转换为一棵树 const int N=1e4+100;const i ...
- 【POJ - 3694】Network(对dfn求lca 或 缩点+lca 或 边双连通+并查集)
题干: 网络管理员管理大型网络.该网络由N台计算机和成对计算机之间的M链路组成.任何一对计算机都通过连续的链接直接或间接连接,因此可以在任何两台计算机之间转换数据.管理员发现某些链接对网络至关重要,因 ...
- SDUT 2603:Rescue The Princess
Rescue The Princess Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 Several days ago, a b ...
最新文章
- AI技术出海 - 阿里云GPU服务器助力旷视勇夺4项世界第一
- 算法整理:Boyer-Moore 投票算法
- Kubernetes 如何打赢容器之战?
- JMS学习(1):MS基本概念
- BitMap-BitSet(JDK1.8)基本使用入门
- 去百度/阿里/腾讯…做测试的,都是什么样的人?
- webApp 开发技术要点总结
- php mysql安装配置_转载:PHP,MySQL的安装与配置
- 关于动态库和静态库的总结
- Python闭包装饰器笔记
- mingw32位下载以及windows下安装
- 36个精美完整网站网页完整源码HTML+CSS+JS
- 文件上传到服务器出错(Permission denied)
- 唐平中讲座笔记 Reinforcement mechanism design 20171107
- 零基础学编程的我的心路历程
- 计算机教学中扩词扩句的应用,【教学设计】学习扩写 ——部编人教版九下第一单元写作...
- js 身份证号隐藏中间数字
- 最小包围球(附完整代码)
- 音视频流媒体————基本概念
- 用matlab实现高斯信道建模