叫network的题真是多。。。
思路:先一次tarjan缩点,得到一颗树,每次 加边,两个端点到它们的lca之间的边都不再是桥,所以每一次我们都可以通过暴力求出lca,然后统计出少了多少条桥,但是暴力统计时,会遇到某些边在之前就不是桥的情况,我们用并查集来跳过这些边(每一次加边就把lca路径上的点都合并到一个集合里去,这里根用最上面的点,到时如果遇到这种点,直接可以跳到它们的根上去)
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; const int maxn=110010; const int maxm=210010; int head[maxn]; int head2[maxn]; int DFN[maxn]; int low[maxn]; int deep[maxn]; int fa[maxn]; int block[maxn]; int pre[maxn]; int st[maxn]; int instack[maxn]; int tot,tot2,top,ord,sccnum,icase; struct node { int next,to,id; }edge[maxm<<2],edge2[maxm<<2]; void init() { memset(DFN,-1,sizeof(DFN)); memset(head,-1,sizeof(head)); memset(head2,-1,sizeof(head2)); memset(low,0,sizeof(low)); memset(instack,0,sizeof(instack)); tot=tot2=ord=sccnum=top=0; } void addedge(int u,int v,int w) { edge[tot].to=v; edge[tot].id=w; edge[tot].next=head[u]; head[u]=tot++; } void addedge2(int u,int v) { edge2[tot2].to=v; edge2[tot2].next=head2[u]; head2[u]=tot2++; } int find(int x) { if(x==fa[x]) return x; return fa[x]=find(fa[x]); } void dfs(int u,int f,int d) { pre[u]=f; deep[u]=d; for(int i=head2[u];i!=-1;i=edge2[i].next) { int v=edge2[i].to; if(v==f) continue; dfs(v,u,d+1); } } void tarjan(int u,int x) { DFN[u]=low[u]=++ord; instack[u]=1; st[top++]=u; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(edge[i].id==x) continue; if(DFN[v]==-1) { tarjan(v,edge[i].id); low[u]=min(low[u],low[v]); } else if(instack[v]) low[u]=min(low[u],DFN[v]); } int v; if(DFN[u]==low[u]) { ++sccnum; do { v=st[--top]; instack[v]=0; block[v]=sccnum; }while(v!=u); } } int LCA(int a,int b) { while(a!=b) { if(deep[a]>deep[b]) a=pre[a]; else if(deep[a]<deep[b]) b=pre[b]; else { a=pre[a]; b=pre[b]; } a=find(a); b=find(b); } return a; } void solve(int n) { tarjan(1,-1); for(int u=1;u<=n;u++) { for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(block[u]==block[v]) continue; addedge2(block[u],block[v]); } } for(int i=1;i<=sccnum;i++) fa[i]=i; int cnt=sccnum-1; dfs(1,-1,0); int q,a,b,lca; scanf("%d",&q); printf("Case %d:\n", icase++); while(q--) { scanf("%d%d",&a,&b); a=block[a]; b=block[b]; if(a==b) { printf("%d\n",cnt); continue; } a=find(a); b=find(b); lca=LCA(a,b); int x=0; while(a!=lca) { x++; fa[a]=lca; a=pre[a]; a=find(a); } while(b!=lca) { x++; fa[b]=lca; b=pre[b]; b=find(b); } cnt-=x; printf("%d\n",cnt); } } int main() { int n,m; int u,v; icase=1; while(scanf("%d%d",&n,&m)!=EOF) { if(!n&&!m) break; init(); for(int i=1;i<=m;i++) { scanf("%d%d",&u,&v); addedge(u,v,i); addedge(v,u,i); } solve(n); puts(""); } return 0; }
