/**
problem: http://poj.org/problem?id=3694 问每加一条边后剩下多少桥
因为是无向图,所以使用tarjan缩点后会成一棵树并维护pre数组
在树上连一条边(a,b)减少的桥数就是
a点到a点和b点的最近公共祖先(lca)的所有边+b点到a点和b点的最近公共祖先的所有边
在算桥的同时将这些点缩成一个点
即每个点color = 最近公共祖先color
同时维护pre数组 每个点的pre = 最近公共祖先的pre 即可
**/
#include<stdio.h>
#include<stack>
#include<queue>
#include<algorithm>
using namespace std; const int MAXN = ;
const int MAXM = ; class Graphics{
private:
struct Edge{
int to, next;
bool bridge;
}edge[MAXM];
struct Point{
int dfn, low, color;
}point[MAXN];
int first[MAXN], pre[MAXN], sign, sumOfPoint, dfnNum, colorNum, bridge;
bool vis[MAXN];
stack<int> stk;
queue<int> bfs;
void tarjan(int u, int preEdge = -){
point[u].low = dfnNum;
point[u].dfn = dfnNum ++;
vis[u] = true;
stk.push(u);
for(int i = first[u]; i != -; i = edge[i].next){
int to = edge[i].to;
if((i^) == preEdge) continue;
if(!point[to].dfn){
pre[to] = u; ///如果下一个点没被访问过则更新一下下个点的pre
tarjan(to, i);
point[u].low = min(point[u].low, point[to].low);
if(point[to].low > point[u].dfn){
edge[i].bridge = true;
edge[i^].bridge = true;
bridge ++;
}
}else if(vis[to]){
point[u].low = min(point[to].dfn, point[u].low);
}
}
if(point[u].dfn == point[u].low){
vis[u] = false;
point[u].color = ++ colorNum;
while(stk.top() != u){
pre[stk.top()] = pre[u]; ///缩点时,该环中的所有点pre等于时间戳最小点的pre
point[stk.top()].color = colorNum;
vis[stk.top()] = false;
stk.pop();
}
stk.pop();
}
}
public:
void clear(int n){
sumOfPoint = n;
for(int i = ; i <= n; i ++){
first[i] = -;
pre[i] = -;
vis[i] = ;
point[i].dfn = ;
}
sign = colorNum = bridge = ;
dfnNum = ;
while(!stk.empty()) stk.pop();
}
void addEdgeOneWay(int u, int v){
edge[sign].to = v;
edge[sign].next = first[u];
edge[sign].bridge = false;
first[u] = sign ++;
}
void addEdgeTwoWay(int u, int v){
addEdgeOneWay(u, v);
addEdgeOneWay(v, u);
}
void tarjanAllPoint(){
for(int i = ; i <= sumOfPoint; i ++){
if(!point[i].dfn)
tarjan(i);
}
}
int getAns(int a, int b){
for(int i = ; i <= colorNum; i ++){
vis[i] = false;
}
vis[point[a].color] = true;
vis[point[b].color] = true;
int lca, lcacolor, ta = a, tb = b;
while(true){
if(ta != -) ta = pre[ta];
if(tb != -) tb = pre[tb];
if(vis[point[ta].color]){
lcacolor = point[ta].color;
lca = ta;
break;
}
if(vis[point[tb].color]){
lcacolor = point[tb].color;
lca = tb;
break; }
vis[point[ta].color] = true;
vis[point[tb].color] = true;
}
while(point[a].color != lcacolor){
for(int i = first[a]; i != -; i = edge[i].next){
int to = edge[i].to;
if(to == pre[a] && edge[i].bridge){
bridge --;
edge[i].bridge = false;
edge[i^].bridge = false;
break;
}
}
point[a].color = lcacolor;
int tmp = pre[a];
pre[a] = pre[lca];
a = tmp;
}
while(point[b].color != lcacolor){
for(int i = first[b]; i != -; i = edge[i].next){
int to = edge[i].to;
if(to == pre[b] && edge[i].bridge){
bridge --;
edge[i].bridge = false;
edge[i^].bridge = false;
break;
}
}
point[b].color = lcacolor;
int tmp = pre[b];
pre[b] = pre[lca];
b = tmp;
}
addEdgeTwoWay(a, b);
return bridge;
}
}graph; int main(){
int n, m, cas = ;
while(scanf("%d%d", &n, &m) != EOF && m + n){
graph.clear(n);
while(m --){
int a, b;
scanf("%d%d", &a, &b);
graph.addEdgeTwoWay(a, b);
}
graph.tarjanAllPoint();
int q;
scanf("%d", &q);
printf("Case %d:\n", cas ++);
while(q --){
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", graph.getAns(a, b));
}
putchar('\n');
}
return ;
}

poj 3694 Network : o(n) tarjan + O(n) lca + O(m) 维护 总复杂度 O(m*q)的更多相关文章

  1. POJ 3694 Network(无向图求桥+重边处理+LCA)

    题目大意: 给你一个无向图,然后再给你一个Q代表有Q次询问,每一次加一条边之后还有几座桥.在这里要对重边进行处理. 每次加入一条边之后,在这条搜索树上两个点的公共祖先都上所有点的桥都没了. 这里重边的 ...

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

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

  3. POJ 3694——Network——————【连通图,LCA求桥】

    Network Time Limit:5000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Stat ...

  4. Poj 1236 Network of Schools (Tarjan)

    题目链接: Poj 1236 Network of Schools 题目描述: 有n个学校,学校之间有一些单向的用来发射无线电的线路,当一个学校得到网络可以通过线路向其他学校传输网络,1:至少分配几个 ...

  5. POJ 3694 Network (tarjan + LCA)

    题目链接:http://poj.org/problem?id=3694 题意是给你一个无向图n个点,m条边,将m条边连接起来之后形成一个图,有Q个询问,问将u和v连接起来后图中还有多少个桥. 首先用t ...

  6. POJ 3694 Network(Tarjan求割边+LCA)

    Network Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 10969   Accepted: 4096 Descript ...

  7. poj 3694 Network 【Tarjan】+【LCA】

    <题目链接> 题目大意: 给一个无向图,该图只有一个连通分量.然后查询q次,q < 1000, 求每次查询就增加一条边,求剩余桥的个数. 解题分析: 普通的做法就是在每加一条边后,都 ...

  8. poj 3694 Network(双连通分量)

    题目:http://poj.org/problem?id=3694 #include <iostream> #include <cstring> #include <cs ...

  9. poj 3694 Network(割边+lca)

    题目链接:http://poj.org/problem?id=3694 题意:一个无向图中本来有若干条桥,有Q个操作,每次加一条边(u,v),每次操作后输出桥的数目. 分析:通常的做法是:先求出该无向 ...

随机推荐

  1. owin解决跨域js请求

    最近在用owin打了一个建议的http的api服务,但遇到了js跨域访问的问题,后来在网上找到了答案,已帮助遇到此问题的人 1.首先nuget先按着owin依赖的包,然后至关重要的一步是引用Micro ...

  2. 用于模式匹配的String方法和RegExp方法

    上一节总结了创建正则表达式的语法,这一篇笔者总结了用于模式匹配的String四个方法:search().replace().match().split()以及用于模式匹配的RegExp两个方法exec ...

  3. mysql什么情况下会触发表锁

    锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所有数 ...

  4. Win10系统安装iis的方法【图文教程】

    1.在win10系统中的开始按钮点击右键,选择控制面板: 2.从控制面板选择“程序”: 然后选择“启用或关闭windows功能” 3.从列表中选择Internet Infomation Service ...

  5. 在Windows 7 上安装 Mapnik

    环境: 1.Windows 7_64位 2.Python 2.7_32位 步骤: 1.下载 Mapnik SDK   http://mapnik.org/download/  我下载的是  Windo ...

  6. Python学习系列----第六章 数据结构

    本章主要讲的是python中重要的四种数据结构,分别是列表.元组.字典和集合. 6.1 列表 list 是处理一组有序项目的数据结构,即你可以在一个列表中存储一个序列的项目.列表中的项目应该包括在方括 ...

  7. window medio player 完美代码

    var arr = [               '<object width="240" height="240" align="basel ...

  8. DataBase Migration 使用笔记

    Add-Migration 新建数据库迁移版本 Update-Database -Verbose 更新到数据库(-Verbose 显示详细信息) Update-Database –TargetMigr ...

  9. poj 1753、2965枚举

    1753题目链接 题目大意: 一个4乘4的棋盘,上面放满了正反两面分别为黑和白的棋子,翻转一个棋子会让这个棋子上下左右的棋子也翻转,给定一个初始状态,求使所有棋子颜色相同所需的最少翻转次数. 解题思路 ...

  10. 解决SQLite打开已有路径下的db问题

    最近遇到的需要加载已有路径下(sd card下)db的问题,找了一下资料,以下是解决的方法,仅供参考(转载自eoe): SQLiteOpenHelper 是Android框架为我们提供的一个非常好的数 ...