题意:给一个n顶点m条边的无向图,有若干条桥,现在有q个询问,每次询问在这个图里面添加一条边,问添加这条边之后剩下的桥的数目有多少
思路:百度了很久题解..主要是丝毫不会LCA..做法就是先求出图中的桥和双连通分量,缩点(这里不用真的缩点,其实DFS留下的low和pre数组,记录每个点的父节点就能形成一颗深搜树,只要在出桥的时候标记一下然后LCA的时候利用pre数组就可以,因为u和v的最近公共祖先pre一定相同),树上的肯定都是桥,那么如果X和Y在同一个分量中就对桥边数毫无影响,如果是不同的缩点,那么连接起来之后,u到LCA到v这个环里面的桥都要删除,向上找它们的LCA,因为它们之间连了一条边,所以这些点到它们的LCA之间的边都不是割边了,找LCA时,先将两点上升到同一层次,然后一起再向上找父亲节点,其间遇到桥就把桥的标记删除,并且答案减1。
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <ctime>
#include <cmath>
#include <cctype>
using namespace std;
#define maxn 100005
#define maxm 100000+10
#define LL long long
int cas=1,T;
int n,m;
int sum = 0;
int dfs_clock; //时钟,每访问一个结点增1
vector<int>G[maxn]; //图
int cut; //记录桥数
int bridge[maxn];
int father[maxn];
int pre[maxn]; //pre[i]表示i结点被第一次访问到的时间戳,若pre[i]==0表示还未被访问
int low[maxn]; //low[i]表示i结点及其后代能通过反向边连回的最早的祖先的pre值
//bool iscut[maxn]; //标记i结点是不是一个割点
//int cut[maxn]; //切割这个结点后的儿子数
//求出以u为根节点(u在DFS树中的父节点是fa)的树的所有割点和桥
//初始调用dfs(root,-1)
int dfs(int u,int fa)
{
int flag = 0;
int lowu=pre[u]=++dfs_clock;
int child = 0; //子结点数目
for (int i = 0;i<G[u].size();i++)
{
int v = G[u][i];
if (v==fa && !flag)
{
flag++;
continue;
}
if (!pre[v])
{
child++; //未访问过的结点才能算是u的孩子
int lowv = dfs(v,u);
father[v]=u; //记录v的父亲
lowu = min(lowu,lowv);
if (lowv>pre[u])
{
cut++;
bridge[v]=1;
}
/*if (lowv >=pre[u])
{
iscut[u]=1; //u是割点
cut[u]++;
if (lowv > pre[u]) //(u,v)边时桥
// printf("qiao")
}*/
}
else/* if (pre[v] <pre[u] && v!=fa) */ //v!=fa确保了(u,v)是从u到v的反向边
{
lowu = min(lowu,pre[v]);
}
}
return low[u]=lowu;
}
void init()
{
dfs_clock = 0;
sum=0;
memset(pre,0,sizeof(pre));
memset(father,0,sizeof(father));
memset(bridge,0,sizeof(bridge));
cut=0;
// memset(iscut,0,sizeof(iscut));
// memset(cut,0,sizeof(cut));
for (int i = 0;i<=n;i++)
G[i].clear();
}
int lca(int u,int v)
{
int cut1=0;
while (pre[u]>pre[v])
{
if (bridge[u])
{
cut1++;
bridge[u]=0;
}
u=father[u];
}
while (pre[v]>pre[u])
{
if (bridge[v])
{
cut1++;
bridge[v]=0;
}
v=father[v];
}
while (u!=v)
{
if (bridge[u])
{
bridge[u]=0;
cut1++;
}
if (bridge[v])
{
bridge[v]=0;
cut1++;
}
u=father[u];
v=father[v];
}
return cut1;
}
int main()
{
//freopen("in","r",stdin);
while (scanf("%d%d",&n,&m)!=EOF && n)
{
init();
for (int i = 0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,-1);
int q;
scanf("%d",&q);
printf("Case %d:\n",cas++);
while (q--)
{
int u,v;
scanf("%d%d",&u,&v);
cut-=lca(u,v);
printf("%d\n",cut);
}
}
//printf("time=%.3lf",(double)clock()/CLOCKS_PER_SEC);
return 0;
}