poj3694 边-双连通分量+lca
题意:先给了一张无向图,然后依次加边,每次求桥的数量
题解:先用一次tarjan,我们可以标记桥的位置和记录桥的数量同时记录fa数组,然后更新边的时候我们可以用lca,因为在tarjan缩点之后得到了一颗树,当连接a,b节点时,可以直观的看出从a,b的最近公共祖先到a,b之间所有的桥都会消失,我们可以不断更新桥的标记来输出答案,同时之前连的边对后面的(除了桥数以外)结果没有影响
#include<map> #include<set> #include<list> #include<cmath> #include<queue> #include<stack> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define fi first #define se second #define mp make_pair #define pb push_back #define pii pair<int,int> #define C 0.5772156649 #define pi acos(-1.0) #define ll long long #define mod 1000000007 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 using namespace std; using namespace __gnu_cxx; const double g=10.0,eps=1e-7; const int N=100000+10,maxn=100000+10,inf=0x3f3f3f; struct edge{ int to,Next; }e[N*6]; int head[N],cnt,fa[N]; int dfn[N],low[N]; int index,num,iscut[N]; void add(int u,int v) { e[cnt].to=v; e[cnt].Next=head[u]; head[u]=cnt++; e[cnt].to=u; e[cnt].Next=head[v]; head[v]=cnt++; } void init(int n) { for(int i=1;i<=n;i++) { dfn[i]=low[i]=iscut[i]=0; } memset(head,-1,sizeof head); index=num=cnt=0; } void tarjan(int u,int f) { dfn[u]=low[u]=++index; int k=0; for(int i=head[u];~i;i=e[i].Next) { int x=e[i].to; if(x==f&&!k) { k++; continue; } if(!dfn[x]) { fa[x]=u; tarjan(x,u); low[u]=min(low[u],low[x]); if(low[x]>dfn[u])num++,iscut[x]=1; } else low[u]=min(low[u],dfn[x]); } } void lca(int a,int b) { if(dfn[a]>dfn[b])swap(a,b); while(dfn[a]>dfn[b]) { if(iscut[a])num--; iscut[a]=0; a=fa[a]; } while(a!=b) { if(iscut[a])num--; if(iscut[b])num--; iscut[a]=iscut[b]=0; a=fa[a];b=fa[b]; } } int main() { int n,m,res=1; while(~scanf("%d%d",&n,&m)) { if(!n&&!m)break; init(n); for(int i=0;i<m;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b); } fa[1]=1; tarjan(1,-1); printf("Case %d:\n",res++); int q; scanf("%d",&q); while(q--) { int a,b; scanf("%d%d",&a,&b); lca(a,b); printf("%d\n",num); } puts(""); } return 0; } /************ ************/