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. 文件上传以及JS链式结构

    文件上传: 文件上传使用FileUpload控件,使用控件的SaveAs方法,需要绝对路径. 获取文件的绝对路径:Server.MapPath(相对路径); 或许要上传文件的本身名字用.FileNam ...

  2. 2.2、CDH 搭建Hadoop在安装(安装Java Development Kit)

    第2步:安装Java Development Kit 要安装Oracle JDK,您可以使用Cloudera Manager安装Cloudera提供的版本,也可以直接安装Oracle的其他版本. 继续 ...

  3. Using promises

    [Using promises] 过去,异步方法这样写: function successCallback(result) { console.log("It succeeded with ...

  4. 在project窗口中快速定位文件

    [在project窗口中快速定位文件] 点击带圆圈的小叉叉按钮,这个时候Project中就会定位到当前文件目录下了. 参考:http://blog.csdn.net/hyr83960944/artic ...

  5. putty加了密钥ssh不能登陆,PuTTY:server refused our key问题的解决(转)

    直接上方法:禁用系统的selinux功能,命令#setenforce0,但重启系统,selinux仍然启用.根治方法:更改SElinux的配置文件/etc/selinux/config,修改SELIN ...

  6. NBU 还原LINUX ORACLE 数据库(EHR)

    一.E-HR数据库(全备)恢复 目录 一.E-HR数据库(全备)恢复... 1 1. 使用bplist 命令读取备份文件... 1 2. 启动到nomount状态... 2 3. 利用rman还原控制 ...

  7. dns隧道 dns2tcpd

    有些网络的防火墙设置只允许端口53的UDP流量,就不能通过tcp搭建隧道,这种情况下我们可以通过UDP搭建DNS隧道,通过搭建一个DNS服务器委派的子域,这个子域因为使我们自己搭建的主机,这时候就可以 ...

  8. python全栈开发 什么是python python命名及循环

    python全栈 一.  python介绍: 1.    python起源 2.    主要应用领域; web,人工智能,云计算,系统运维. 1.1   python是一门什么语言? python是一 ...

  9. HOOK -- DLL的远程注入技术详解(1)

    DLL的远程注入技术是目前Win32病毒广泛使用的一种技术.使用这种技术的病毒体通常位于一个DLL中,在系统启动的时候,一个EXE程序会将这个DLL加载至某些系统进程(如Explorer.exe)中运 ...

  10. POJ-1426.Findthemultiple.(BFS)

    一开始模拟了一波大数取余结果超时了,最后改成long long过了emmm... 本题大意:给出一个200以内的数n,让你找出一个m使得m % n == 0,要求m只有1和0组成. 本题思路:BFS模 ...