题意:给你一个连通的图,然后每加一条边,就求一次图中的桥数;
解题思路:这题一看,就知道第一步肯定是缩点,先求边双连通分量,然后就是并查集的事情了,由于缩点后的图是一棵树,以某一点为根,在缩点后的图中找到每个点的深度,然后用并查集记录父结点,当加入一条边时,先使边的两端找到深度一样的父结点,再一路一找到第一个相同的父结点为止,每过一条桥,桥数就减一,然后把这条边标记为不是桥,输出桥数,
这里其实有求LCA的过程,只是这里面我没用到LCA的相关算法,所以感觉这题考的是边双连通缩点+并查集
1735msG++代码
#include<cstdio> #include<algorithm> using namespace std; typedef struct edge { int to; edge *next; }edge; edge *last[100005],*g[100005],*b[100005]; int dfn[100005],low[100005],n,m,num,btch,belone[100005],st[100005],top,Q,u,v,ans,bin[100005],level[100005]; bool flag,vis[100005],iscut[100005]; void tarjan(int i,int fa) { dfn[i]=low[i]=++num; st[top++]=i; int flag=1; last[i]=g[i]; while(last[i]) { int v=last[i]->to; last[i]=last[i]->next; if(fa==v&&flag) { flag=0; continue; } if(dfn[v]==-1) { tarjan(v,i); low[i]=min(low[v],low[i]); if(dfn[i]<low[v]) { int x; btch++; do { x=st[--top]; belone[x]=btch; } while(x!=v); } } else { low[i]=min(low[i],dfn[v]);} } } void dfs(int u,int d) { int i; level[u]=d; vis[u]=true; last[u]=b[u]; while(last[u]!=NULL) { int v=last[u]->to; if(!vis[v]) { bin[v]=u; iscut[v]=true; dfs(v,d+1); } last[u]=last[u]->next; } } void tarjan_lca(int u,int v) { while(level[u]>level[v]) { if(iscut[u]) { ans--; iscut[u]=false; } u=bin[u]; } while(level[v]>level[u]) { if(iscut[v]) { ans--; iscut[v]=false; } v=bin[v]; } while(u!=v) { if(iscut[u]) { ans--; iscut[u]=0; } if(iscut[v]) { ans--; iscut[v]=0; } u=bin[u]; v=bin[v]; } } int main() { int i,j,x,y,t=1; edge *p; while(scanf("%d %d",&n,&m)&&(m+n)) { top=num=btch=0; for(i=0;i<=n;i++) { dfn[i]=-1; g[i]=b[i]=NULL; belone[i]=0; bin[i]=i; vis[i]=false; } for(i=0;i<m;i++) { scanf("%d %d",&x,&y); p=(edge*)malloc(sizeof(edge)); p->to=y;p->next=NULL; if(g[x]==NULL) { last[x]=g[x]=p; } else { last[x]->next=p; last[x]=last[x]->next; } p=(edge*)malloc(sizeof(edge)); p->to=x;p->next=NULL; if(g[y]==NULL) { last[y]=g[y]=p; } else { last[y]->next=p; last[y]=last[y]->next; } } /*for(i=1;i<=n;i++) { printf("%d :",i); last[i]=g[i]; while(last[i]) { printf(" %d",last[i]->to); last[i]=last[i]->next; } printf("\n"); }*/ tarjan(1,0);//边双连通缩点 edge *q; for(i=1;i<=n;i++)//建图 { p=g[i]; while(p!=NULL) { int v=p->to; if(belone[i]!=belone[v]) { q=(edge*)malloc(sizeof(edge)); q->to=belone[v];q->next=NULL; if(b[belone[i]]==NULL) { last[belone[i]]=b[belone[i]]=q; } else { last[belone[i]]->next=q; last[belone[i]]=last[belone[i]]->next; } } p=p->next; } } /*for(i=0;i<=btch;i++) { printf("%d :",i); last[i]=b[i]; while(last[i]) { printf(" %d",last[i]->to); last[i]=last[i]->next; } printf("\n"); }*/ ans=btch; dfs(0,0); printf("Case %d:\n",t++); scanf("%d",&Q); for(i=0;i<Q;i++) { flag=false; scanf("%d %d",&u,&v); if(belone[u]==belone[v]) printf("%d\n",ans); else { tarjan_lca(belone[u],belone[v]); printf("%d\n",ans); } } printf("\n"); } return 0; }