1. /**
  2. problem: http://poj.org/problem?id=3694
  3.  
  4. 问每加一条边后剩下多少桥
  5. 因为是无向图,所以使用tarjan缩点后会成一棵树并维护pre数组
  6. 在树上连一条边(a,b)减少的桥数就是
  7. a点到a点和b点的最近公共祖先(lca)的所有边+b点到a点和b点的最近公共祖先的所有边
  8. 在算桥的同时将这些点缩成一个点
  9. 即每个点color = 最近公共祖先color
  10. 同时维护pre数组 每个点的pre = 最近公共祖先的pre 即可
  11. **/
  12. #include<stdio.h>
  13. #include<stack>
  14. #include<queue>
  15. #include<algorithm>
  16. using namespace std;
  17.  
  18. const int MAXN = ;
  19. const int MAXM = ;
  20.  
  21. class Graphics{
  22. private:
  23. struct Edge{
  24. int to, next;
  25. bool bridge;
  26. }edge[MAXM];
  27. struct Point{
  28. int dfn, low, color;
  29. }point[MAXN];
  30. int first[MAXN], pre[MAXN], sign, sumOfPoint, dfnNum, colorNum, bridge;
  31. bool vis[MAXN];
  32. stack<int> stk;
  33. queue<int> bfs;
  34. void tarjan(int u, int preEdge = -){
  35. point[u].low = dfnNum;
  36. point[u].dfn = dfnNum ++;
  37. vis[u] = true;
  38. stk.push(u);
  39. for(int i = first[u]; i != -; i = edge[i].next){
  40. int to = edge[i].to;
  41. if((i^) == preEdge) continue;
  42. if(!point[to].dfn){
  43. pre[to] = u; ///如果下一个点没被访问过则更新一下下个点的pre
  44. tarjan(to, i);
  45. point[u].low = min(point[u].low, point[to].low);
  46. if(point[to].low > point[u].dfn){
  47. edge[i].bridge = true;
  48. edge[i^].bridge = true;
  49. bridge ++;
  50. }
  51. }else if(vis[to]){
  52. point[u].low = min(point[to].dfn, point[u].low);
  53. }
  54. }
  55. if(point[u].dfn == point[u].low){
  56. vis[u] = false;
  57. point[u].color = ++ colorNum;
  58. while(stk.top() != u){
  59. pre[stk.top()] = pre[u]; ///缩点时,该环中的所有点pre等于时间戳最小点的pre
  60. point[stk.top()].color = colorNum;
  61. vis[stk.top()] = false;
  62. stk.pop();
  63. }
  64. stk.pop();
  65. }
  66. }
  67. public:
  68. void clear(int n){
  69. sumOfPoint = n;
  70. for(int i = ; i <= n; i ++){
  71. first[i] = -;
  72. pre[i] = -;
  73. vis[i] = ;
  74. point[i].dfn = ;
  75. }
  76. sign = colorNum = bridge = ;
  77. dfnNum = ;
  78. while(!stk.empty()) stk.pop();
  79. }
  80. void addEdgeOneWay(int u, int v){
  81. edge[sign].to = v;
  82. edge[sign].next = first[u];
  83. edge[sign].bridge = false;
  84. first[u] = sign ++;
  85. }
  86. void addEdgeTwoWay(int u, int v){
  87. addEdgeOneWay(u, v);
  88. addEdgeOneWay(v, u);
  89. }
  90. void tarjanAllPoint(){
  91. for(int i = ; i <= sumOfPoint; i ++){
  92. if(!point[i].dfn)
  93. tarjan(i);
  94. }
  95. }
  96. int getAns(int a, int b){
  97. for(int i = ; i <= colorNum; i ++){
  98. vis[i] = false;
  99. }
  100. vis[point[a].color] = true;
  101. vis[point[b].color] = true;
  102. int lca, lcacolor, ta = a, tb = b;
  103. while(true){
  104. if(ta != -) ta = pre[ta];
  105. if(tb != -) tb = pre[tb];
  106. if(vis[point[ta].color]){
  107. lcacolor = point[ta].color;
  108. lca = ta;
  109. break;
  110. }
  111. if(vis[point[tb].color]){
  112. lcacolor = point[tb].color;
  113. lca = tb;
  114. break;
  115.  
  116. }
  117. vis[point[ta].color] = true;
  118. vis[point[tb].color] = true;
  119. }
  120. while(point[a].color != lcacolor){
  121. for(int i = first[a]; i != -; i = edge[i].next){
  122. int to = edge[i].to;
  123. if(to == pre[a] && edge[i].bridge){
  124. bridge --;
  125. edge[i].bridge = false;
  126. edge[i^].bridge = false;
  127. break;
  128. }
  129. }
  130. point[a].color = lcacolor;
  131. int tmp = pre[a];
  132. pre[a] = pre[lca];
  133. a = tmp;
  134. }
  135. while(point[b].color != lcacolor){
  136. for(int i = first[b]; i != -; i = edge[i].next){
  137. int to = edge[i].to;
  138. if(to == pre[b] && edge[i].bridge){
  139. bridge --;
  140. edge[i].bridge = false;
  141. edge[i^].bridge = false;
  142. break;
  143. }
  144. }
  145. point[b].color = lcacolor;
  146. int tmp = pre[b];
  147. pre[b] = pre[lca];
  148. b = tmp;
  149. }
  150. addEdgeTwoWay(a, b);
  151. return bridge;
  152. }
  153. }graph;
  154.  
  155. int main(){
  156. int n, m, cas = ;
  157. while(scanf("%d%d", &n, &m) != EOF && m + n){
  158. graph.clear(n);
  159. while(m --){
  160. int a, b;
  161. scanf("%d%d", &a, &b);
  162. graph.addEdgeTwoWay(a, b);
  163. }
  164. graph.tarjanAllPoint();
  165. int q;
  166. scanf("%d", &q);
  167. printf("Case %d:\n", cas ++);
  168. while(q --){
  169. int a, b;
  170. scanf("%d%d", &a, &b);
  171. printf("%d\n", graph.getAns(a, b));
  172. }
  173. putchar('\n');
  174. }
  175. return ;
  176. }

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. HashMap put、get方法源码分析

    HashMap.java的实现是面试必问的问题. JDK版本 java version "1.8.0_91" Java(TM) SE Runtime Environment (bu ...

  2. scss-@while指令

    @while是一个循环指令,其后跟着一个表达式,如果表达式的返回值为false,则停止循环. scss代码实例如下: $i: 6; @while $i > 0 { .item-#{$i} { w ...

  3. ActiveMQ VirtualTopic

    参考网址: http://activemq.apache.org/virtual-destinations.html http://blog.csdn.net/kimmking/article/det ...

  4. xshell连不上虚拟机linux的解决办法

    1.找到Linux系统的ip地址 输入命令   ifconfig 2.打开本地网络连接 将VMnet1的ip地址设置为和虚拟机ip同一网段的ip 比如虚拟机Linux系统的ip为   192.168. ...

  5. 【起航计划 036】2015 起航计划 Android APIDemo的魔鬼步伐 35 App->Service->Messenger Service Messenger实现进程间通信

    前面LocalService 主要是提供同一Application中组件来使用,如果希望支持不同应用或进程使用Service.可以通过Messenger.使用Messgener可以用来支持进程间通信而 ...

  6. sql产生流水号

    一个产生流水号(年月日+5位流水号)的存储过程 现在客户有一个需求,要产生一个流水号,如090611+000001(年月日+五位流水号),此流水号在数据库表中是主键,且为varchar类 型.如果在当 ...

  7. Windows7建立无线热点

    很实用的技巧,加以记录. 最初我是想使用connectify的,不过安装这个软件之后,发现有线账号登不上了,所以就选择使用Windows7自带的工具了. 首先以管理员身份运行cmd. 进入之后cd到c ...

  8. collectd配置

    udp proxy - 192.168.48.112 cat > /etc/collectd_25801.conf << EOF Hostname "kvm-48-112& ...

  9. SqlServer50条常用查询语句

    Student(S#,Sname,Sage,Ssex) 学生表 Course(C#,Cname,T#) 课程表 SC(S#,C#,score) 成绩表 Teacher(T#,Tname) 教师表 问题 ...

  10. Python 调度算法 死锁 静动态链接(七)

    1 select poll epoll的区别 基本上select有3个缺点: 连接数受限 查找配对速度慢 数据由内核拷贝到用户态 poll改善了第一个缺点 epoll改了三个缺点. (1)select ...