题意:给一个n个点的无向图,m条双向边,保证没有重边和自环,图连通,有q个询问,给两个点,S和T,问从S到T有多少条割边。
思路:看到这题第一反应就是求双连通分量,然后缩点,因为在同一个双连通分量内肯定没有割边,然后缩点后原图就变成了一棵树,因为保证原图连通,所以得到的也只有一颗树,树中的边即为原图中的割边,于是问题就转化成求树中两点的距离了,用LCA即可解决。先贴一个代码。
#include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> #define maxn 100010 using namespace std; struct edge { int to; int next; int num; }e[3][maxn<<2]; int box[3][maxn],cnt[3]; void init() { memset(box,-1,sizeof(box)); memset(cnt,0,sizeof(cnt)); } void add(int from,int to,int num,int t) { e[t][cnt[t]].to=to; e[t][cnt[t]].num=num; e[t][cnt[t]].next=box[t][from]; box[t][from]=cnt[t]++; } int pre[maxn]; int low[maxn]; int bridge[maxn]; int bcnt=0; int cnt0; void bridge_search(int now,int fa) { int t; int v,w; low[now]=pre[now]=++cnt0; for(t=box[0][now];t+1;t=e[0][t].next) { v=e[0][t].to; if(v==fa) continue; if(!pre[v]) { bridge_search(v,now); if(low[v]<low[now]) low[now]=low[v]; if(low[v]>pre[now]) { bridge[e[0][t].num]=1; } } else { if(low[now]>pre[v]) low[now]=pre[v]; } } } int Bridge(int n) { int i; cnt0=0; memset(pre,0,sizeof(pre)); memset(low,0,sizeof(low)); memset(bridge,0,sizeof(bridge)); bcnt=0; for(i=1;i<=n;i++) { if(!pre[i]) { bridge_search(i,0); } } return bcnt; } int vis[maxn]; int dist[maxn]; void Dfs(int now,int num) { low[now]=num; vis[now]=1; int t,v,nn; for(t=box[0][now];t+1;t=e[0][t].next) { v=e[0][t].to,nn=e[0][t].num; if(bridge[nn]) continue; if(!vis[v]) { Dfs(v,num); } } } void solve(int n)//Ëõµã { int i,sum=0; memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); for(i=1;i<=n;i++) { if(!low[i]) Dfs(i,++sum); } for(i=1;i<=n;i++) { int t,v; for(t=box[0][i];t+1;t=e[0][t].next) { v=e[0][t].to; if(low[i]!=low[v]) { add(low[i],low[v],0,1); add(low[v],low[i],0,1); } } } } void dfs(int now,int deep) { dist[now]=deep; vis[now]=1; int t,v; for(t=box[1][now];t+1;t=e[1][t].next) { v=e[1][t].to; if(!vis[v]) { dfs(v,deep+1); } } } int f[maxn]; void finit(int n) { int i; for(i=0;i<=n;i++) f[i]=i; } int find(int x) { if(x==f[x]) return x; return f[x]=find(f[x]); } int ans[maxn]; void lca(int now) { f[now]=now; vis[now]=1; int t,v,x; for(t=box[1][now];t+1;t=e[1][t].next) { v=e[1][t].to; if(!vis[v]) { lca(v); f[v]=now; } } for(t=box[2][now];t+1;t=e[2][t].next) { v=e[2][t].to,x=e[2][t].num; if(vis[v]==2) { int tt=find(v); ans[x]=dist[now]+dist[v]-2*dist[tt]; } } vis[now]=2; } int main() { //freopen("dd.txt","r",stdin); int n,m,i,a,b,q; scanf("%d%d",&n,&m); init(); for(i=1;i<=m;i++) { scanf("%d%d",&a,&b); add(a,b,i,0); add(b,a,i,0); } memset(ans,0,sizeof(ans)); Bridge(n); solve(n); memset(vis,0,sizeof(vis)); dfs(1,0); scanf("%d",&q); for(i=1;i<=q;i++) { scanf("%d%d",&a,&b); if(low[a]!=low[b]) { add(low[a],low[b],i,2); add(low[b],low[a],i,2); } } memset(vis,0,sizeof(vis)); lca(1); for(i=1;i<=q;i++) printf("%d\n",ans[i]); return 0; }