POJ3694 Network - Tarjan + 并查集
Description
给定$N$个点和 $M$条边的无向联通图, 有$Q$ 次操作, 连接两个点的边, 问每次操作后的图中有几个桥
Solution
首先Tarjan找出边双联通分量, 每个双联通分量缩成一个点, 就构成了一棵树, 每一条树边都是桥。
执行连$u, v$ 边时, 用并查集跳到没有桥的深度最浅并且深度比$lca$深的点, 将它与父节点的并查集合并, 再接着跳。
每跳一次, 桥的数量就减少$1$。
另外感谢Iowa 神犇提醒我$cut$数组要开$M << 1$, 不是 $N << 1$, 拯救了$RE$崩溃的我呜呜
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rd read()
using namespace std; const int N = 1e5 + 1e4;
const int M = 2e5 + 1e4; int n, m, dfn[N], low[N], cnt;
int head[N], tot;
int Head[N], Tot;
int col[N], col_num, father[N], ans;
int top[N], son[N], size[N], f[N], dep[N];
int cut[M << ]; struct edge {
int nxt, to;
}E[M << ], e[M << ]; int read() {
int X = , p = ; char c = getchar();
for(; c > '' || c < ''; c = getchar()) if(c == '-') p = -;
for(; c >= '' && c <= ''; c = getchar()) X = X * + c - '';
return X * p;
} void add(int u, int v) {
e[++tot].to = v;
e[tot].nxt = head[u];
head[u] = tot;
} void Add(int u, int v) {
E[++Tot].to = v;
E[Tot].nxt = Head[u];
Head[u] = Tot;
} void dfs1(int u) {
size[u] = ;
for(int i = Head[u]; i; i = E[i].nxt) {
int nt = E[i].to;
if(nt == f[u]) continue;
f[nt] = u;
dep[nt] = dep[u] + ;
dfs1(nt);
size[u] += size[nt];
if(size[nt] > size[son[u]]) son[u] = nt;
}
} void dfs2(int u) {
if(!son[u]) return;
top[son[u]] = top[u];
dfs2(son[u]);
for(int i = Head[u]; i; i = E[i].nxt) {
int nt = E[i].to;
if(nt == f[u] || nt == son[u]) continue;
top[nt] = nt;
dfs2(nt);
}
} int LCA(int x, int y) {
for(; top[x] != top[y];) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
x = f[top[x]];
}
if(dep[x] < dep[y]) swap(x, y);
return y;
} int get(int x) {
return father[x] == x? x : father[x] = get(father[x]);
} void merg(int x, int y) {
x = get(x); y = get(y);
father[x] = y;
} int ch(int x) {
return ((x + ) ^ ) - ;
} void tarjan(int u, int pre) {
dfn[u] = low[u] = ++cnt;
for(int i = head[u]; i; i = e[i].nxt) {
if(i == ch(pre)) continue;
int nt = e[i].to;
if(!dfn[nt]) {
tarjan(nt, i);
low[u] = min(low[u], low[nt]);
if(low[nt] > dfn[u]) {
cut[ch(i)] = cut[i] = ;
ans++;
}
}
else low[u] = min(low[u], dfn[nt]);
}
} void dfs(int u) {
col[u] = col_num;
for(int i = head[u]; i; i = e[i].nxt) {
int nt = e[i].to;
if(col[nt] || cut[i]) continue;
dfs(nt);
//blo[col_num].push_back(nt);
}
} void work() {
ans = Tot = tot = cnt = col_num = ;
memset(Head, , sizeof(Head));
memset(head, , sizeof(head));
memset(cut, , sizeof(cut));
memset(dfn, , sizeof(dfn));
memset(col, , sizeof(col));
memset(son, , sizeof(son));
memset(size, , sizeof(size));
for(int i = ; i <= m; ++i) {
int u = rd, v = rd;
add(u, v); add(v, u);
}
for(int i = ; i <= n; ++i) if(!dfn[i]) tarjan(i, );
for(int i = ; i <= n; ++i) if(!col[i]) {
++col_num; dfs(i);
}
for(int i = ; i <= tot; ++i) {
int x = e[i].to, y = e[ch(i)].to;
if(col[x] == col[y]) continue;
Add(col[x], col[y]);
}
for(int i = ; i <= col_num; ++i) father[i] = i;
dfs1();
top[] = ; dfs2();
int T = rd;
for(; T; T--) {
int u = col[rd], v = col[rd], lca = LCA(u, v);
u = get(u); v = get(v);
while(dep[u] > dep[lca]) {
merg(u, f[u]);
u = get(u);
ans --;
}
while(dep[v] > dep[lca]) {
merg(v, f[v]);
v = get(v);
ans --;
}
printf("%d\n", ans);
}
} int main()
{
for(int i = ; ; ++i) {
n = rd; m = rd;
if(!n && !m) return ;
printf("Case %d:\n", i);
work();
putchar('\n');
}
}
POJ3694 Network - Tarjan + 并查集的更多相关文章
- LCA tarjan+并查集POJ1470
LCA tarjan+并查集POJ1470 https://www.cnblogs.com/JVxie/p/4854719.html 不错的一篇博客啊,让我觉得LCA这么高大上的算法不是很难啊,嘻嘻嘻 ...
- POJ3694:Network(并查集+缩点+lca)
Network Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 13172 Accepted: 4774 题目链接:htt ...
- POJ 2236 Wireless Network(并查集)
传送门 Wireless Network Time Limit: 10000MS Memory Limit: 65536K Total Submissions: 24513 Accepted ...
- poj 2236:Wireless Network(并查集,提高题)
Wireless Network Time Limit: 10000MS Memory Limit: 65536K Total Submissions: 16065 Accepted: 677 ...
- POJ3694 Network(Tarjan双联通分图 LCA 桥)
链接:http://poj.org/problem?id=3694 题意:给定一个有向连通图,每次增加一条边,求剩下的桥的数量. 思路: 给定一个无向连通图,添加一条u->v的边,求此边对图剩余 ...
- POJ 2236 Wireless Network (并查集)
Wireless Network 题目链接: http://acm.hust.edu.cn/vjudge/contest/123393#problem/A Description An earthqu ...
- BestCoder冠军赛 - 1009 Exploration 【Tarjan+并查集缩点】
[题意] 给一个图,这个图中既有有向边,又有无向边,每条边只能走一次,问图中是否存在环. 最多10^6个点,10^6个无向边,10^6个有向边 [题解] 因为既有有向边又有无向边,所以不能单纯的用ta ...
- POJ 3694 Network(并查集缩点 + 朴素的LCA + 无向图求桥)题解
题意:给你一个无向图,有q次操作,每次连接两个点,问你每次操作后有几个桥 思路:我们先用tarjan求出所有的桥,同时我们可以用并查集缩点,fa表示缩点后的编号,还要记录每个节点父节点pre.我们知道 ...
- POJ 2236:Wireless Network(并查集)
Wireless Network Time Limit: 10000MS Memory Limit: 65536K Total Submissions: 36363 Accepted: 150 ...
随机推荐
- SSH 登录时出现如下错误:Disconnected:No supported authentication methods available
SSH 登录时出现如下错误:Disconnected:No supported authentication methods available 更新时间:2017-06-07 13:26:11 ...
- MySQL可以通过phpmyadmin连接,但是无法通过SqlYog(Windows)或Sequel Pro(Mac)下进行远程连接
更改数据库密码: update user set password=passworD("sunjingyu0509!") where user='root'; flush priv ...
- java-学习8
方法的声明及使用 public class function { public static void main(String[] args) { printInfo();//调用printInfo( ...
- OpenCV之Vec3f
Vec3f表示的是3通道float类型的 Vect,就相当于3通道float类型的图像(这是其中一个具体化),解释可以从源代码中看出来. 下面给出一个具体的例子: Vec3f point = Vec3 ...
- centos7防火墙以设置以及关闭selinux
一.CentOS 7.X 关闭SELinux 1.查看 getenforce permissive 或者 enforcing模式 2.临时设置 setenforce 1 成为permissive模式 ...
- flashfxp key密钥
flashfxp3.41中文版注册码:(适合最新版本) 推荐(尚未被封的 Realkey) FLASHFXPvACq2ssbvAAAAAC1W7cJKQTzmx77zmqJICvA7d3WnUtWNX ...
- 用PLSQL Developer 查看Oracle的存储过程
1 2.输入 3.具体存储过程
- 反射实现 AOP 动态代理模式(Spring AOP 的实现原理)
枚举 在某些情况下,一个类的对象是有限而且固定的,比如季节类,它只有4个对象.这种实例有限而且固定的类,在Java里被称为枚举类. 枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编 ...
- 二叉树的镜像(python)
题目描述 操作给定的二叉树,将其变换为源二叉树的镜像. 输入描述: 二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ ...
- pta l3-20(至多删三个字符)
题目链接:https://pintia.cn/problem-sets/994805046380707840/problems/994805046946938880 题意:给定一个长度<=106 ...