Po姐说
把能进行会议的国家之间都用并查集连接起来,然后把每个进行过会议的国家扔进队列跑BFS,将搜到的国家用并查集连接
最终答案等于每个单点的出度个数+2*C(每个集合的大小,2)
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<set>
#define V G[p].v
using namespace std;
typedef long long ll;
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x)
{
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=100005;
namespace TSet{
int fat[N],rank[N],size[N];
void init(int n){
for (int i=1;i<=n;i++) fat[i]=i,rank[i]=0,size[i]=1;
}
int Fat(int u){
return u==fat[u]?u:fat[u]=Fat(fat[u]);
}
void Union(int x,int y){
x=Fat(x),y=Fat(y); if (x==y) return;
if (rank[x]>rank[y]) swap(x,y);
if (rank[x]==rank[y]) rank[x]++;
fat[x]=y; size[y]+=size[x];
}
};
int n,m;
ll ans;
int Q[N],vst[N];
int l=-1,r=-1;
set<int> M[N];
typedef set<int>::iterator ITER;
int main()
{
using namespace TSet;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
int iu,iv;
read(n); read(m); init(n);
for(int i=1;i<=m;i++)
read(iu),read(iv),M[iu].insert(iv);
for(int i=1;i<=n;i++)
for(ITER it=M[i].begin();it!=M[i].end();it++)
if (M[*it].find(i)!=M[*it].end())
Union(i,*it);
for(int i=1;i<=n;i++)
if (M[i].size()>1)
{
int last=*M[i].begin();
ITER it=M[i].begin(); it++;
for(;it!=M[i].end();it++)
Union(*it,last);
}
for(int i=1;i<=n;i++)
if(size[Fat(i)]>1)
vst[i]=1,Q[++r]=i;
while (l<r)
{
iu=Q[++l];
for(ITER it=M[iu].begin();it!=M[iu].end();it++)
{
Union(iu,*it);
if(!vst[*it]) vst[*it]=1,Q[++r]=*it;
}
}
for(int i=1;i<=n;i++)
if (Fat(i)==i)
{
if(size[i]==1)
ans+=M[i].size();
else
ans+=(ll)size[i]*(size[i]-1);
}
printf("%lld\n",ans);
return 0;
}