http://poj.org/problem?id=3694
2008 Asia Hefei Regional Contest Online,by USTC
维护一张图中桥的个数,支持动态加边(加边次数为q次)。
1≤|V|≤100000,1≤|E|≤200000,1≤q≤1000
对于初始的图,用tarjan算法生成一棵DFS树以及其DFS序,并同时求出最开始时整张图中的桥的个数,将除了桥边以外的所有边(u,v)中的点u与点v在并查集中合并,这样我们就能得到初始时整张图去掉桥边之后的联通块。
注意DFS序有一个非常好的特性:对于点x而言,点x的DFS序标号<它的左子树中的所有节点的DFS序标号<它的右子树中所有节点的的DFS序标号,这个特性会在下面得到运用。
对于之后的每次加边(u′,v′)操作,有以下两种情况:
Case 1.u与v不在一条链上,设v在u的右边。让v先不断向上爬,直到爬到u与v的LCA即lca(u,v)上,其间会经过若干联通块,若经过一条边E链接了两个不同的联通块,则表明访问了一个桥边,标记减少了一条桥边(因为加入了边(u,v)后这些桥边都将消失)。v爬到了lca(u,v)后,就让u也爬到lca(u,v)上,处理方法与v的相同
Case 2.u与v在一条链上,不妨设u在v上面,就让v爬到u即可,处理方法与Case 1相同。
#include
#include
#include
#include
#define MAXV 110000
#define MAXE 410000
using namespace std;
struct edge
{
int u,v,next;
}edges[MAXE];
int head[MAXV],nCount=0;
void AddEdge(int U,int V)
{
edges[++nCount].u=U;
edges[nCount].v=V;
edges[nCount].next=head[U];
head[U]=nCount;
}
int f[MAXV];
int findSet(int x)
{
if(f[x]==x) return x;
return f[x]=findSet(f[x]);
}
int dfn[MAXV],low[MAXV],idx=0;
int father[MAXV];
int bridgeNum=0;
bool Union(int u,int v)
{
int rootu=findSet(u),rootv=findSet(v);
if(rootu==rootv) return false;
f[rootu]=rootv;
return true;
}
void tarjan(int u,int fa)
{
dfn[u]=low[u]=++idx;
for(int p=head[u];p!=-1;p=edges[p].next)
{
int v=edges[p].v;
if(v==fa) continue;
if(!dfn[v])
{
father[v]=u;
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]) bridgeNum++;
else
Union(u,v);
}
else
low[u]=min(low[u],dfn[v]);
}
}
int solve(int u,int v) //加入边u-v
{
if(findSet(u)==findSet(v)) return bridgeNum; //加入边u-v之前u和v是联通的
if(dfn[u]>dfn[v]) swap(u,v); //保证dfs序中u在v左边
while(dfn[u]if(Union(father[v],v))
bridgeNum--;
v=father[v];
}
while(u!=v)
{
if(Union(u,father[u]))
bridgeNum--;
u=father[u];
}
return bridgeNum;
}
int main()
{
int n,m,T=0;
while(scanf("%d%d",&n,&m)!=EOF&&!(!n&&!m))
{
printf("Case %d:\n",++T);
nCount=0;
memset(head,-1,sizeof(head));
memset(father,0,sizeof(father));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
for(int i=0;ifor(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
AddEdge(u,v);
AddEdge(v,u);
}
father[1]=1;
tarjan(1,1);
int q;
scanf("%d",&q);
while(q--)
{
int u,v;
scanf("%d%d",&u,&v);
printf("%d\n",solve(u,v));
}
}
return 0;
}