给定一个无向无环图,保证连通,求每加入一条给定的边图中还剩下多少桥。
双联通缩点重新建图后,再用lca在线算法解。
lca算法参考斌神http://www.cnblogs.com/kuangbin/p/3184884.html
这个版本的lca思路大致是先topsort,再用并查集分别从查询的两点向根节点回溯,直到两个点碰撞。效率我分析不出来,但看得出效率很高,每次查询都对后面查询做了工作。
代码:
#include<iostream> #include<cstdio> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<cstring> #include<algorithm> #define rep(i,a,b) for(int i=(a);i<(b);i++) #define rev(i,a,b) for(int i=(a);i>=(b);i--) #define clr(a,x) memset(a,x,sizeof a) #define inf 0x3f3f3f3f typedef long long LL; using namespace std; const int eps=0.00000001; const int maxn=100005; const int maxm=400006; int first[maxn],low[maxn],dfn[maxn],fa[maxn],if_add[maxn]; int nex[maxm],u[maxm],v[maxm],w[maxm]; int belong[maxn],stck[maxn]; int n,m,ecnt,index,bridge,block,top,ecntt; bool ins[maxn],vcut[maxn],ecut[maxm]; void tarjan(int s,int pre) { dfn[s]=low[s]=++index; stck[top++]=s; ins[s]=1; int son=0; for(int e=first[s];~e;e=nex[e]) { if(v[e]==pre)continue; if(!dfn[v[e]]) { son++; tarjan(v[e],s); low[s]=min(low[s],low[v[e]]); if(low[v[e]]>dfn[s]) { bridge++; ecut[e]=1; ecut[e^1]=1; } if(s!=pre&&low[v[e]]>=dfn[s]) { vcut[s]=1; if_add[s]++; } } else if(ins[v[e]])low[s]=min(low[s],dfn[v[e]]); } if(s==pre&&son>1)vcut[s]=1,if_add[s]=son-1; if(low[s]==dfn[s]) { int vv; block++; do { vv=stck[--top]; ins[vv]=0; belong[vv]=block; }while(vv!=s); } } void add_(int a,int b,int c) { u[ecnt]=a; v[ecnt]=b; w[ecnt]=c; ecut[ecnt]=0; nex[ecnt]=first[a]; first[a]=ecnt++; } void add__(int a,int b,int c) { u[ecntt]=a; v[ecntt]=b; w[ecntt]=c; ecut[ecntt]=0; nex[ecntt]=first[a]; first[a]=ecntt++; } void solve() { clr(dfn,0); clr(if_add,0); clr(vcut,0); index=bridge=block=top=0; for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i,i); } void suodian() { ecntt=0; clr(first,-1); for(int i=0;i<ecnt;i++) if(ecut[i])add__(belong[u[i]],belong[v[i]],0); } int ans,dep[maxn],done[maxn]; void lca_bfs(int s) { clr(dep,-1); dep[s]=0; done[s]=0; fa[s]=-1; queue<int>q; q.push(s); while(!q.empty()) { int x=q.front();q.pop(); for(int e=first[x];~e;e=nex[e]) { if(dep[v[e]]!=-1)continue; dep[v[e]]=dep[x]+1; done[v[e]]=1; fa[v[e]]=x; q.push(v[e]); } } } void lca(int s,int t) { if(dep[s]>dep[t])swap(s,t); while(dep[s]<dep[t]) { if(done[t]) { ans--; done[t]=0; } t=fa[t]; } while(s!=t) { if(done[s]) { ans--; done[s]=0; } if(done[t]) { ans--; done[t]=0; } s=fa[s]; t=fa[t]; } } int main() { int a,b,c,cas=1; while(~scanf("%d%d",&n,&m)&&(n||m)) { clr(first,-1);ecnt=0; for(int i=0;i<m;i++) { scanf("%d%d",&a,&b); if(a!=b) { add_(a,b,c),add_(b,a,c); } } solve(); suodian(); ans=block-1; lca_bfs(1); printf("Case %d:\n",cas++); scanf("%d",&c); while(c--) { scanf("%d%d",&a,&b); lca(belong[a],belong[b]); printf("%d\n",ans); } printf("\n"); } }