-
D - Network
- POJ - 3694
- 一个无向图可以有重边,下面q个操作,每次在两个点间连接一条有向边,每次连接后整个无向图还剩下多少桥
- 解题思路:边连通分量+LCA。首先运行一次tarjan,求出桥和缩点,那么无向图将缩点为一棵树,树边正好是原来的桥。每次连接两点,看看这两点是不是在同一个缩点内,如果是,那么缩点后的树没任何变化,如果两点属于不同的缩点,那么连接起来,然后找这两个缩点的LCA,因为从点u到LCA再到点v再到点u,将形成环,里面的树边都会变成不是桥。
-
#include<iostream> #include<cstdio> #include<string.h> #include<string> #include<algorithm> #include<stack> #include<queue> #include<cmath> using namespace std; const int M=400005; const int N=100005; int n,m,ans,q,u,v,cs; struct node { int v,nxt; } edge[M]; int head[N],edn; void add(int u,int v) { edge[edn].v=v; edge[edn].nxt=head[u]; head[u]=edn; edn++; } int fa[N],d[N],dfn[N],low[N],bccnum,index; bool mark[N],ef[M]; void tarjan(int u) { dfn[u]=low[u]=++index; for(int i=head[u]; i!=-1; i=edge[i].nxt) { int v=edge[i].v; if(ef[i])continue; ef[i]=ef[i^1]=1; if(!dfn[v]) { fa[v]=u; d[v]=d[u]+1; tarjan(v); low[u]=min(low[u],low[v]); if(dfn[u]<low[v]) { ans++; mark[v]=true; } } else low[u]=min(low[u],dfn[v]); } } void lca(int a,int b) { if(d[a]>d[b])swap(a,b); while(d[b]>d[a]) { if(mark[b]) ans--,mark[b]=false; b=fa[b]; } while(a!=b) { if(mark[a]) ans--,mark[a]=false; if(mark[b]) ans--,mark[b]=false; a=fa[a]; b=fa[b]; } } void init() { memset(head,-1,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(d,0,sizeof(d)); memset(mark,false,sizeof(mark)); memset(ef,false,sizeof(ef)); index=ans=bccnum=edn=0; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0) break; printf("Case %d:\n",++cs); init(); for(int i=1; i<=m; i++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } tarjan(1); scanf("%d",&q); for(int cs=1; cs<=q; cs++) { scanf("%d%d",&u,&v); lca(u,v); printf("%d\n",ans); } printf("\n"); } return 0; }
D - Network POJ - 缩点判桥TARJAN+LCA
最新推荐文章于 2021-03-18 12:15:10 发布