poj 3694双联通缩点+LCA
题意:给你一个无向连通图,每次加一条边后,问图中桥的数目。
思路:先将图进行双联通缩点,则缩点后图的边就是桥,然后dfs记录节点深度,给出(u,v)使其节点深度先降到同一等级,然后同时降等级直到汇合到同一个点为止。途中直接进行删边处理且桥的数目减少。
代码:
#include<iostream> #include<cstring> #include<cstdio> #include<vector> using namespace std; #define MAXN 100005 struct E { int to,next; }edge[10*MAXN],e[10*MAXN]; int tt,tot,index,cnt,n,m,k; int h[MAXN],head[MAXN],vis[MAXN],dfn[MAXN],low[MAXN],fa[MAXN],level[MAXN],pre[MAXN],res[MAXN]; bool bridge[MAXN]; void addedge(int u,int v) { edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; edge[tot].to=u; edge[tot].next=head[v]; head[v]=tot++; } void adde(int u,int v) { e[tt].to=v; e[tt].next=h[u]; h[u]=tt++; } int find(int x) { if(x!=fa[x]) fa[x]=find(fa[x]); return fa[x]; } void tarjan(int u,int f) { int i,v; vis[u]=1; dfn[u]=low[u]=++index; for(int i=head[u];i!=-1;i=edge[i].next) { v=edge[i].to; if(vis[v]==0) { tarjan(v,u); low[u]=min(low[u],low[v]); if(dfn[u]<low[v])//判断桥 { cnt++; res[cnt]=i; } else //合并 { u=find(u); v=find(v); fa[v]=u; } } else if(vis[v]==1&&v!=f) { low[u]=min(low[u],dfn[v]); } } vis[u]=2; } void lca_dfs(int u,int d) { int i,v; level[u]=d; vis[u]=1; for(int i=h[u];i!=-1;i=e[i].next) { v=e[i].to; if(!vis[v]) { pre[v]=u; lca_dfs(v,d+1); } } } void lca(int u,int v) { while(level[u]>level[v]) { if(bridge[u]) { cnt--; bridge[u]=0; } u=pre[u]; } while(level[v]>level[u]) { if(bridge[v]) { cnt--; bridge[v]=0; } v=pre[v]; } while(u!=v) { if(bridge[u]) { cnt--; bridge[u]=0; } if(bridge[v]) { cnt--; bridge[v]=0; } u=pre[u]; v=pre[v]; } } void Init() { memset(h,-1,sizeof(h)); memset(head,-1,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(vis,0,sizeof(vis)); memset(bridge,false,sizeof(bridge)); memset(level,0,sizeof(level)); tot=tt=index=cnt=0; for(int i=1;i<=n;i++) { fa[i]=i; } } int main() { freopen("in.txt","r",stdin); int t=1; while(scanf("%d%d",&n,&m)!=EOF,(n||m)) { Init(); for(int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); addedge(u,v); } for(int i=1;i<=n;i++) if(!vis[i]) tarjan(i,-1); int a,b; for(int u=1;u<=n;u++) //缩点后再构图 { for(int j=head[u];j!=-1;j=edge[j].next) { int v=edge[j].to; a=find(u); b=find(v); if(a!=b) { adde(a,b); } } } memset(vis,0,sizeof(vis)); lca_dfs(fa[1],1); for(int i=1;i<=cnt;i++) { bridge[find(edge[res[i]].to)]=1; } printf("Case %d:\n",t++); scanf("%d",&k); while(k--) { int i,j; scanf("%d%d",&i,&j); int x=find(i),y=find(j); if(x!=y) { lca(x,y); } printf("%d\n",cnt); } printf("\n"); } return 0; }