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 + 并查集的更多相关文章

  1. LCA tarjan+并查集POJ1470

    LCA tarjan+并查集POJ1470 https://www.cnblogs.com/JVxie/p/4854719.html 不错的一篇博客啊,让我觉得LCA这么高大上的算法不是很难啊,嘻嘻嘻 ...

  2. POJ3694:Network(并查集+缩点+lca)

    Network Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 13172   Accepted: 4774 题目链接:htt ...

  3. POJ 2236 Wireless Network(并查集)

    传送门  Wireless Network Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 24513   Accepted ...

  4. poj 2236:Wireless Network(并查集,提高题)

    Wireless Network Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 16065   Accepted: 677 ...

  5. POJ3694 Network(Tarjan双联通分图 LCA 桥)

    链接:http://poj.org/problem?id=3694 题意:给定一个有向连通图,每次增加一条边,求剩下的桥的数量. 思路: 给定一个无向连通图,添加一条u->v的边,求此边对图剩余 ...

  6. POJ 2236 Wireless Network (并查集)

    Wireless Network 题目链接: http://acm.hust.edu.cn/vjudge/contest/123393#problem/A Description An earthqu ...

  7. BestCoder冠军赛 - 1009 Exploration 【Tarjan+并查集缩点】

    [题意] 给一个图,这个图中既有有向边,又有无向边,每条边只能走一次,问图中是否存在环. 最多10^6个点,10^6个无向边,10^6个有向边 [题解] 因为既有有向边又有无向边,所以不能单纯的用ta ...

  8. POJ 3694 Network(并查集缩点 + 朴素的LCA + 无向图求桥)题解

    题意:给你一个无向图,有q次操作,每次连接两个点,问你每次操作后有几个桥 思路:我们先用tarjan求出所有的桥,同时我们可以用并查集缩点,fa表示缩点后的编号,还要记录每个节点父节点pre.我们知道 ...

  9. POJ 2236:Wireless Network(并查集)

    Wireless Network Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 36363   Accepted: 150 ...

随机推荐

  1. python基础学习 Day19 面向对象的三大特性之多态、封装 property的用法(1)

    一.课前内容回顾 继承作用:提高代码的重用性(要继承父类的子类都实现相同的方法:抽象类.接口) 继承解释:当你开始编写两个类的时候,出现了重复的代码,通过继承来简化代码,把重复的代码放在父类中. 单继 ...

  2. table tr 加入背景色之后 去掉td之间的空隙

    给table加样式  border-collapse:collapse;

  3. GO注释

    1.GO资源简介 由于生物系统的惊人复杂性和需要分析的数据集的不断增加,生物医学研究越来越依赖于以可计算的形式存储的知识.基因本体论(GO)项目为基因功能和基因产物的可计算知识提供了目前最全面的资源. ...

  4. ReactCSSTransitionGroup

    [ReactCSSTransitionGroup] ReactCSSTransitionGroup is a high-level API based on ReactTransitionGroup  ...

  5. webservice客户端 get delete post 请求

    package com.cn.eport.util.common; import java.io.IOException; import java.util.List; import org.apac ...

  6. 自定义sql server 聚合涵数

    using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Micr ...

  7. Nginx 到底可以做什么

    本文只针对Nginx在不加载第三方模块的情况能处理哪些事情,由于第三方模块太多所以也介绍不完,当然本文本身也可能介绍的不完整,毕竟只是我个人使用过和了解到过得,欢迎留言交流. Nginx能做什么 反向 ...

  8. [剑指Offer]22-链表中倒数第k个结点

    题目链接 https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId=13&tqId=11167&t ...

  9. Java09-java语法基础(八)java中的方法

    Java09-java语法基础(八)java中的方法 一.方法(函数/过程):是一个程序块,可以完成某种功能 1.java中方法的定义格式 [访问控制修饰符]  返回值类型  方法名(参数列表){ 方 ...

  10. Activity 的启动过程深入学习

    手机应用也是一个app,每一个应用的icon都罗列在Launcher上,点击icon触发onItemClick事件. 我们要启动「淘宝」这个App,首先我们要在清单文件定义默认启动的Activity信 ...