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 ...
随机推荐
- 关于CSS中的浮动
在页面布局中我们经常会用到浮动的布局,浮动元素会影响到后面页面的布局效果.例如下面: .box{ background: yellow; float: left; } .box2{ width: 20 ...
- java 开学第四周
package english; import java.io.File; import java.util.Scanner; import java.io.FileNotFoundException ...
- gradle 很好用的么
Gradle 其实是很好用的 2017, Apr 14 by Tesla Ice Zhang Gradle 是一款使用 Kotlin (划掉) Groovy 编写的 JVM 构建工具,其易用性和 Ma ...
- day15模块内容
1.生成器表达式 先说三元表达式如下 res = [i for i in range(10) if 1 > 5] 这样res就是一个列表6,7,8,9] 只要在这个基础上稍加调整,如下 方括号改 ...
- char和varchar查询速度、存储空间比较详解(转)
转:http://tech.diannaodian.com/dw/data/sql/2011/1005/135572.html 一.数据行结构 1.char(n): 系统分配n个字节给此字段,不管字段 ...
- Mysql 索引与Key
如果只是key的话,就是普通索引. mysql的key和index多少有点令人迷惑,单独的key和其它关键词结合的key(primary key)实际表示的意义是不同,这实际上考察对数据库体系结构的了 ...
- json 相关知识
一:json标准格式: 标准JSON的合法符号:{(左大括号) }(右大括号) "(双引号) :(冒号) ,(逗号) [(左中括号) ](右中括号) JSON字符串:特殊字符可在 ...
- 2 c++对象被使用前要先被初始化
虽然有些时候int x;会被初始化为0,但是也可能不会,这就造成随机初始值会影响我们程序的运行. 类成员变量初始化顺序是依照其声明顺序而来的.基类要早于派生类别初始化. 构造函数最好使用成员初值列: ...
- Django的auth【认证】模块简介
首先我们先来复习一下路由别名如何使用,这里仅仅复习一下二级路由的路由别名该如何使用 ·1.在视图函数中使用二级路由别名,需要加上app的名称+“:”+ “路由别名” from django.urls ...
- listView悬浮头部的简单实现
简而言之 为listView设置onScrollListener 当滑动时 firstVisibleItem>=要悬浮的 item的position时 让悬浮部分显示 否则隐藏 其实就是 ...