题解
我们可以统计每一个点的度数,对于边(u,v)(u,v)(u,v)而言,如果duu<duvdu_u<du_vduu<duv或者在度数相同时u<vu<vu<v,则从uuu连接一条vvv的边,否则由vvv连向uuu。
因此三元环的形态一定是由度数小或字典序较小的点连向其它两个点,其它两个点又是有一条边相连的。
我们可以枚举每一个度数最小或在度数相同时字典序最小的节点,然后将每一个点做上标记。在将每一个连出去的点,再枚举向外连接的点,判断是否存在标记。
具体就是一个玄学的三重循环。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 200000;
int n, m, ans = 0;
int u[N], v[N], du[N], tag[N];
vector <int> a[N];
bool cmp(int p1,int p2) {
if (du[p1] == du[p2]) return p1 < p2;
else return du[p1] < du[p2];
}
int main(void)
{
scanf("%d %d", &n, &m);
for (int i=1;i<=m;++i)
{
scanf("%d %d", u+i, v+i);
du[u[i]] ++, du[v[i]] ++;
}
for (int i=1;i<=m;++i)
{
if (cmp(u[i],v[i]))
a[u[i]].push_back(v[i]);
else a[v[i]].push_back(u[i]);
}
for (int i=1;i<=n;++i)
{
for (int j=0;j<a[i].size();++j)
tag[a[i][j]] = i;
for (int j=0;j<a[i].size();++j) {
int p = a[i][j];
for (int k=0;k<a[p].size();++k)
if (tag[a[p][k]] == i) ans ++;
}
}
cout<<ans<<endl;
return 0;
}