双连通缩点后的图上任意边都是桥,且它是一棵树。
由此可知,若新加的一条边处于同一个双联通分量,那么答案不变。
否则,新加的边使得树上多出了一个环,且环上的桥都没有了,所以这两点路径上的边都要减少,预处理每个点的父亲和深度,那么求两点的路径直接暴力向上爬就行了,注意标记边只能减少一次。
#include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<algorithm> #include<map> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define maxn 100005 #define maxm 2000005 struct node { int to,vis,next; }e[maxm],e2[maxm]; int belong[maxn],vis[maxn],dfn[maxn],low[maxn],cnt,bridge,col,stack[maxn],top,fa[maxn],head[maxn],head2[maxn],en,en2,ans; bool use[maxm]; int n,m; int dep[maxn]; void add(int a,int b) { e[en].to=b; e[en].vis=0; e[en].next=head[a]; head[a]=en++; } void add2(int a,int b) { e2[en2].to=b; e2[en2].next=head2[a]; head2[a]=en2++; } void init() { top=cnt=col=bridge=en2=en=0; memset(vis,0,sizeof(vis)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(use,0,sizeof(use)); memset(head2,-1,sizeof(head2)); memset(head,-1,sizeof(head)); } void Tarjan (int u) { int v; vis[u] = 1; dfn[u] = low[u] = ++cnt; stack[top++] = u; for (int i = head[u];i != -1;i = e[i].next) { v = e[i].to; if (e[i].vis) continue; e[i].vis = e[i^1].vis = 1; if (vis[v] == 1) low[u] = min(low[u],dfn[v]); if (!vis[v]) { Tarjan (v); low[u] = min(low[u],low[v]); if (low[v] > dfn[u]) bridge ++; } } if (dfn[u] == low[u]) { ++col; do{ v = stack[--top]; vis[v] = 0; belong[v] = col; }while (u != v); } } void dfs(int now) { for(int i=head2[now];~i;i=e2[i].next) { int to=e2[i].to; if(to!=fa[now]) { dep[to]=dep[now]+1; fa[to]=now; dfs(to); } } } void cal(int a,int b) { if(a==b) return; int root=belong[a];//小优化,可不加 while(a!=b) { if(dep[a]<dep[b]) swap(a,b); if(use[a]==0) ans--; use[a]=1; a=fa[a]; belong[a]=root; } } inline int ReadInt() { char ch = getchar(); int data = 0; while (ch < '0' || ch > '9') { ch = getchar(); } do { data = data*10 + ch-'0'; ch = getchar(); }while (ch >= '0' && ch <= '9'); return data; } int main() { int a,b,q,ca=1; while(~scanf("%d%d",&n,&m)) { if(!n&&!m) break; init(); for(int i=1;i<=m;i++) { a=ReadInt(); b=ReadInt(); add(a,b); add(b,a); } Tarjan(1); ans=col-1; for(int i=1;i<=n;i++) { for(int j=head[i];~j;j=e[j].next) { int to=e[j].to; if(belong[to]!=belong[i]) { add2(belong[i],belong[to]); } } } dep[1]=0; fa[1]=-1; dfs(1); q=ReadInt(); printf("Case %d:\n",ca++); while(q--) { a=ReadInt(); b=ReadInt(); cal(belong[a],belong[b]); printf("%d\n",ans); } puts(""); } return 0; }