好久没写过这么长的代码了,题解东哥讲了那么多,并查集优化还是很厉害的,赶快做做前几天碰到的相似的题。

 #include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std; const int N = 1e5 + , M = 2e5 + ;
int head[N], ver[M * ], Next[M * ];
int dfn[N], low[N], n, m, tot, num;
bool bridge[M * ]; void add(int x, int y)
{
ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
}
void tarjan(int x, int in_edge)
{
dfn[x] = low[x] = ++num;
for(int i = head[x]; i; i = Next[i])
{
int y = ver[i];
if(!dfn[y])
{
tarjan(y, i); ///节点 和 入边
low[x] = min(low[x], low[y]); if(low[y] > dfn[x])
{
bridge[i] = bridge[i ^ ] = true;
}
}
else if(i != (in_edge ^ )) ///搜索树上的边
{
low[x] = min(low[x], dfn[y]);
}
}
}
int c[N], dcc;
void dfs(int x)
{
c[x] = dcc;
for(int i = head[x]; i; i = Next[i])
{
int y = ver[i];
if(c[y] || bridge[i]) continue;
dfs(y);
}
}
const int maxn = N;
///加边
int cnt, h[maxn];
struct edge
{
int to, pre, v;
} e[maxn << ];
void add(int from, int to, int v)
{
cnt++;
e[cnt].pre = h[from]; ///5-->3-->1-->0
e[cnt].to = to;
e[cnt].v = v;
h[from] = cnt;
}
///LCA
int dist[maxn];
int dep[maxn];
int anc[maxn][]; ///2分的父亲节点
void dfs(int u, int fa)
{
for(int i = h[u]; i; i = e[i].pre)
{
int v = e[i].to;
if(v == fa) continue;
dist[v] = dist[u] + e[i].v;
dep[v] = dep[u] + ;
anc[v][] = u;
dfs(v, u);
}
}
void LCA_init(int n)
{
for(int j = ; ( << j) < n; j++)
for(int i = ; i <= n; i++) if(anc[i][j-])
anc[i][j] = anc[anc[i][j-]][j-];
}
int LCA(int u, int v)
{
int log;
if(dep[u] < dep[v]) swap(u, v);
for(log = ; ( << log) < dep[u]; log++);
for(int i = log; i >= ; i--)
if(dep[u] - ( << i) >= dep[v]) u = anc[u][i];
if(u == v) return u;
for(int i = log; i >= ; i--)
if(anc[u][i] && anc[u][i] != anc[v][i])
u = anc[u][i], v = anc[v][i];
return anc[u][];
}
int fa[N];
int Find(int x)
{
if(x == fa[x]) return x;
return fa[x] = Find(fa[x]);
}
int main()
{
int kase = ;
while(scanf("%d %d", &n, &m) != EOF)
{
if(n == && m == ) break;
tot = , dcc = , cnt = ;
for(int i = ; i <= n; i++) head[i] = , dfn[i] = , low[i] = , c[i] = , h[i] = ;
for(int i = ; i <= m * + ; i++) ver[i] = , Next[i] = , bridge[i] = false;
for(int i = ; i <= m; i++)
{
int x, y; scanf("%d %d", &x, &y);
add(x, y), add(y, x);
}
///求桥
for(int i = ; i <= n; i++)
{
if(!dfn[i]) tarjan(i, );
}
///求边双连通分量
for(int i = ; i <= n; i++)
{
if(!c[i])
{
++dcc;
dfs(i);
}
}
///缩点
for(int i = ; i <= tot; i++)
{
int x = ver[i ^ ], y = ver[i];
if(c[x] == c[y]) continue;
add(c[x], c[y], );
}
dfs(, );
LCA_init(dcc);
///并查集初始化
for(int i = ; i <= dcc; i++) fa[i] = i;
int Q; scanf("%d", &Q);
int ans = dcc - ;
printf("Case %d:\n", ++kase);
while(Q--)
{
int x, y; scanf("%d %d", &x, &y);
x = c[x], y = c[y];
int p = LCA(x, y);
x = Find(x);
while(dep[x] > dep[p])
{
fa[x] = anc[x][];
ans--;
x = Find(x);
}
y = Find(y);
while(dep[y] > dep[p])
{
fa[y] = anc[y][];
ans--;
y = Find(y);
}
printf("%d\n", ans);
}
}
return ;
}

POJ 3694 (tarjan缩点+LCA+并查集)的更多相关文章

  1. Poj 3694 Network (连通图缩点+LCA+并查集)

    题目链接: Poj 3694 Network 题目描述: 给出一个无向连通图,加入一系列边指定的后,问还剩下多少个桥? 解题思路: 先求出图的双连通分支,然后缩点重新建图,加入一个指定的边后,求出这条 ...

  2. POJ 3694Network(Tarjan边双联通分量 + 缩点 + LCA并查集维护)

    [题意]: 有N个结点M条边的图,有Q次操作,每次操作在点x, y之间加一条边,加完E(x, y)后还有几个桥(割边),每次操作会累积,影响下一次操作. [思路]: 先用Tarjan求出一开始总的桥的 ...

  3. POJ3694 Network 边双缩点+LCA+并查集

    辣鸡错误:把dfs和ldfs搞混...QAQ 题意:给定一个无向图,然后查询q次,求每次查询就在图上增加一条边,求剩余割边的个数. 先把边双缩点,然后预处理出LCA的倍增数组: 然后加边时,从u往上跳 ...

  4. POJ3694 Network —— 边双联通分量 + 缩点 + LCA + 并查集

    题目链接:https://vjudge.net/problem/POJ-3694 A network administrator manages a large network. The networ ...

  5. Codevs 3287 货车运输 2013年NOIP全国联赛提高组(带权LCA+并查集+最大生成树)

    3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 传送门 题目描述 Description A 国有 n 座 ...

  6. Tarjan 模板,高级并查集

    第一个模板有误!!!! 请见谅!!! 要怪就怪HDU吧,竟然让我过了 第二个模板是正确的.请翻到下面看更新 HDU 1269 评论区居然有人说用并查集过了,其实回想一下 求无向图的连通分量,就是并查集 ...

  7. 【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集

    [题目]D. Best Edge Weight [题意]给定n个点m条边的带边权无向连通图,对每条边求最大边权,满足其他边权不变的前提下图的任意最小生成树都经过它.n,m<=2*10^5,1&l ...

  8. POJ 2762 tarjan缩点+并查集+度数

    Going from u to v or from v to u? Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 15494 ...

  9. Network POJ - 3694(lca并查集+连通图求桥)

    就是求出原先图中的桥的数量,在每一次询问时加入一条新边,求加入当前边后图中剩余的桥的数量 求出原先图中的桥的数量,然后减去新加入边的两端点之间的桥的数量,就是剩余桥的数量.. 用并查集把属于同一集合的 ...

随机推荐

  1. CPP-基础:友元

    友元可以是一个函数,该函数被称为友元函数:友元也可以是一个类,该类被称为友元类. 我们已知道类具有封装和信息隐藏的特性.只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的.非成 ...

  2. C06 变量和存储类型

    目录 全局变量 局部变量 存储类型 全局变量和局部变量 变量的作用域 作用域:某些事物起作用或有效的区域. 变量的使用范围称为变量的作用域. 变量的作用域决定了变量的可操作性和有效性. C语言变量的作 ...

  3. Fortran学习笔记4(循环语句)

    Fortran学习笔记4 Fortran学习笔记4 逻辑运算 循环 Do语句 Do-While循环 循环控制 循环应用实例 逻辑运算 if命令需要和逻辑运算表达式搭配才能起到很好的效果.下面分别列出F ...

  4. 【二分 贪心】bzoj3477: [Usaco2014 Mar]Sabotage

    科学二分姿势 Description Farmer John's arch-nemesis, Farmer Paul, has decided to sabotage Farmer John's mi ...

  5. (45)zabbix报警媒介:SMS

    介绍 服务器安装串口GSM短信猫之后,zabbix可以使用它来发送短信通知给管理员,如下注意事项: 串行设备速度要与GSM猫相匹配(linux下默认为/dev/ttyS0),zabbix无法设置设置串 ...

  6. logstash-基础操作

    一.环境 https://www.cnblogs.com/suffergtf/p/9566145.html 1.收取日志文件到elasticsearch [root@linux-node1 logst ...

  7. Linux磁盘与文件系统管理 之 认识EXT2系统

    1 磁盘组成与分区 1.1 磁盘物理组成 (1)圆形盘片-记录数据 (2)机械手臂及磁头-读写盘片数据 (3)主轴马达-使得机械手臂成功读写数据驱动 1.2 盘片物理组成 (1)扇区-最小物理存储单位 ...

  8. ACM训练联盟周赛 G. Teemo's convex polygon

    65536K   Teemo is very interested in convex polygon. There is a convex n-sides polygon, and Teemo co ...

  9. 合肥工业大学数据结构上机实验代码与实验报告(全)github地址

    我已经将这个学期的所有数据结构上机实验的代码与报告上传到github上了,一直都有这个想法,但没抽出时间来学习git.经过上周简单的练习后,我已经基本学会运营自己的代码仓库了.所有代码都是C++写的类 ...

  10. 【RAID】raid1 raid2 raid5 raid6 raid10的优缺点和做各自raid需要几块硬盘

    Raid 0:一块硬盘或者以上就可做raid0优势:数据读取写入最快,最大优势提高硬盘容量,比如3快80G的硬盘做raid0 可用总容量为240G.速度是一样.缺点:无冗余能力,一块硬盘损坏,数据全无 ...