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

 #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 ;
}

最新文章

  1. mac版Camtasia 2.10破解
  2. golang开发环境配置及Beego框架安装
  3. java.lang.NoClassDefFoundError:
  4. YARN学习笔记 ResourceManager部分
  5. C语言结构体的字节对齐
  6. mysql 数据库插入语句之insert into,replace into ,insert ignore
  7. WPF和Winform的一些界面控件
  8. Java内部抽象类的匿名类初始化
  9. oppo设备怎么样无需root激活XPOSED框架的教程
  10. spring事务相关
  11. koa/redux middleware 深入解析
  12. centos5 升级到centos6
  13. 软件测试常用Linux命令
  14. hdu3861 强连通分量缩点+二分图最最小路径覆盖
  15. Jquery ajax json 不执行success的原因 坑爹
  16. office 2010 正在配置Microsoft Office ...
  17. sort与sorted
  18. 解决charles中文乱码(附代码)
  19. 【BZOJ 3160】 3160: 万径人踪灭 (FFT)
  20. 请写出一段JavaScript代码,要求页面有一个按钮,点击按钮弹出确认框。程序可以判断出用

热门文章

  1. A. Pride (emmmm练习特判的好题)
  2. MFC:AfxParseURL
  3. 全面解读Oracle同义词的概念作用、创建删除查看及Oracle的db link
  4. 【简●解】 LG P2730 【魔板 Magic Squares】
  5. 如何用纯 CSS 创作一个永动的牛顿摆
  6. 【ORACLE】调整序列的当前种子值
  7. Java技术——Java中的内存泄漏
  8. Eclipse如何创建模拟器
  9. Python常用操作符
  10. 【总集】C++ STL类库 vector 使用方法