/* 如果ab都是图的割点,那么答案非0,反之答案是0 把割点处断开后,原图裂成三张不联通的图,大小分别是size1,size2,size3. 求出同时包含这两个割点的图,设大小是size1,那么答案就是(size2-1)*(size3-1) */ #include<bits/stdc++.h> #include<vector> using namespace std; #define ll long long #define N 500005 vector<int>G[N]; int n,m,a,b; int low[N],dfn[N],index,cut[N]; void tarjan(int u,int pre){ low[u]=dfn[u]=++index; int son=0;//统计深搜树上儿子数量 for(auto v:G[u]){ if(v==pre)continue; if(!dfn[v]){ ++son; tarjan(v,u); low[u]=min(low[u],low[v]); if(u!=pre && dfn[u]<=low[v])//非树根割点 cut[u]=true; } else low[u]=min(low[u],dfn[v]); } if(u==pre && son>1)cut[u]=1;//树根割点 } int vis[N],flag; int dfs1(int u){ if(u==a || u==b)flag=1; int size=1;vis[u]=1; for(auto v:G[u]){ if(vis[v])continue; size+=dfs1(v); } return size; } int dfs2(int u){ if(u==a || u==b)flag=1; int size=1;vis[u]=1; for(auto v:G[u]){ if(vis[v])continue; size+=dfs2(v); } return size; } int main(){ int t;cin>>t; while(t--){ scanf("%d%d%d%d",&n,&m,&a,&b); for(int i=1;i<=n;i++)G[i].clear(); for(int i=1;i<=n;i++)low[i]=dfn[i]=cut[i]=vis[i]=0; index=0; for(int i=1;i<=m;i++){ int u,v;scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } tarjan(1,1); if(!cut[a] || !cut[b]){puts("0");continue;} //ab将图分成三块,分别求出这三块的size ll sizea=1;vis[a]=1; for(auto v:G[a]){ if(vis[v])continue; flag=0; int res=dfs1(v); if(!flag)sizea+=res; } for(int i=1;i<=n;i++)vis[i]=0; ll sizeb=1;vis[b]=1; for(auto v:G[b]){ if(vis[v])continue; flag=0; int res=dfs2(v); if(!flag)sizeb+=res; } cout<<(sizea-1)*(sizeb-1)<<' '; } return 0; }