hdu2460-Network:边的双连通分量

题目大意:给出一个无向图以及Q次询问,每次询问增加一条无向边,要求输出增加这条边后剩余的桥的数目。

算法:类似于求割点的方法,先做一次dfs求出所有的桥,并且维护这棵dfs树,当一次询问加入一条边(a,b)之后,会在dfs上形成一个环,在这个环上的桥都变为非桥,这个环肯定经过a和b的LCA,此时我们只需在求LCA的过程中把经过的为桥的树边标记为非桥,同时cnt_bridge--再输出即可。

需要注意的是树边的编号是用树边指向的那个节点的编号来表示的,例如树边<u,v>用编号v表示。

还有就是加入一个#pragma预处理指令可以防止爆栈。

 

  1 #include <iostream>

  2 #include <stdio.h>

  3 #include <cstring>

  4 #include <vector>

  5 using namespace std;

  6 #pragma comment(linker,"/STACk:10240000,10240000")

  7 

  8 const int maxn = 100000 + 10;

  9 int low[maxn],pre[maxn], iscut[maxn], dfs_clock=0;

 10 bool isbridge[maxn];

 11 vector<int> G[maxn];

 12 int cnt_bridge;

 13 int father[maxn];

 14 

 15 int dfs(int u, int fa)

 16 {

 17     father[u]=fa;

 18     int lowu = pre[u] = ++dfs_clock;

 19     int child = 0;

 20     for(int i = 0; i < G[u].size(); i++)

 21     {

 22         int v = G[u][i];

 23         if(!pre[v])   // 没有访问过v

 24         {

 25             child++;

 26             int lowv = dfs(v, u);

 27             lowu = min(lowu, lowv); // 用后代的low函数更新自己

 28             if(lowv > pre[u]) // 判断边(u,v)是否为桥

 29             {

 30                 isbridge[v]=true;

 31                 cnt_bridge++;

 32             }

 33         }

 34         else if(pre[v] < pre[u] && v != fa)

 35         {

 36             lowu = min(lowu, pre[v]); // 用反向边更新自己

 37         }

 38     }

 39     if(fa < 0 && child == 1)

 40         iscut[u] = 0;

 41     return low[u]=lowu;

 42 }

 43 

 44 void init(int n)

 45 {

 46     memset(isbridge,false,sizeof isbridge);

 47     memset(pre,0,sizeof pre);

 48     cnt_bridge=dfs_clock=0;

 49     for(int i=0; i<n; i++)

 50     {

 51         G[i].clear();

 52     }

 53 }

 54 

 55 void LCA(int a,int b)

 56 {

 57     while(pre[a]>pre[b])

 58     {

 59         if(isbridge[a])

 60         {

 61             isbridge[a]=false;

 62             cnt_bridge--;

 63         }

 64         a=father[a];

 65     }

 66     while(pre[b]>pre[a])

 67     {

 68         if(isbridge[b])

 69         {

 70             isbridge[b]=false;

 71             cnt_bridge--;

 72         }

 73         b=father[b];

 74     }

 75     if(a!=b)

 76     {

 77         while(pre[a]>pre[b])

 78         {

 79             if(isbridge[a])

 80             {

 81                 isbridge[a]=false;

 82                 cnt_bridge--;

 83             }

 84             a=father[a];

 85         }

 86         while(pre[b]>pre[a])

 87         {

 88             if(isbridge[b])

 89             {

 90                 isbridge[b]=false;

 91                 cnt_bridge--;

 92             }

 93             b=father[b];

 94         }

 95     }

 96 }

 97 

 98 int main()

 99 {

100 #ifndef ONLINE_JUDGE

101     freopen("in.txt","r",stdin);

102 #endif

103 

104     int n,m,Case=1;

105     while(scanf("%d %d",&n,&m),!(n==0 && m==0))

106     {

107         init(n);

108         for(int i=0; i<m; i++)

109         {

110             int a,b;

111             scanf("%d %d",&a,&b);

112             a--;

113             b--;

114             G[a].push_back(b);

115             G[b].push_back(a);

116         }

117 

118         // 第一次dfs找出所有的桥

119         dfs(0,-1);

120         int Q;

121         cin>>Q;

122         printf("Case %d:\n",Case++);

123         while(Q--)

124         {

125             int a,b;

126             scanf("%d %d",&a,&b);

127             a--;

128             b--;

129             LCA(a,b);

130             printf("%d\n",cnt_bridge);

131             if(Q==0)

132                 printf("\n");

133         }

134     }

135 

136     return 0;

137 }

 

你可能感兴趣的:(NetWork)