无向图三元环计数 (思维,图论)

题目链接
思路:
看完这题第一眼思路是直接枚举两条邻边(m^2),但一看数据范围2e5便知道这个办法不可行,于是考虑将图简化。

简化方法:将原图中度数小的点向度数大的点连一条有向边,如果度数相同便从编号小的向编号大的连边,可以发现这样简化完后的新图是一个DAG(因为如果要成还的话环里的边必然有一条是从度数大的连向度数小的,或者从编号大的连向编号小的,与规则矛盾),而原图中的每个三元环(u,v,w)在新图中一定有一个(u->v,u->w,v->w)的子图与之相对应,我们只需要在新图中枚举每个u的出边,再枚举每个v的出边即可。虽然枚举的时候和我们之前最初的思路差不多,但经过图的简化过后可以证明每个点的出边最多只有根号m条,所以我们在新图上枚举的话复杂度会很神奇的降为O(m√m)即可满足题目要求。
(只能说题解区dalao太强了)
AC代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
#define int long long
const int N = 1e5 + 5, M = 4e5 + 5;
int d[N];
int h[N], e[M], ne[M], idx;
struct node {
	int s, t;
};
vector<node> q;
void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
	return;
}
int st[N];
signed main() {
	int n, m; cin >> n >> m;
	while (m--) {
		int a, b; cin >> a >> b;
		q.push_back({ a,b });
		d[a] += 1;
		d[b] += 1;
	}
	memset(h, -1, sizeof h);
	for (int i = 0; i < q.size(); i++) {
		int ss = q[i].s, tt = q[i].t;
		if (d[ss] < d[tt]) add(ss, tt);
		else if (d[ss] > d[tt]) add(tt, ss);
		else if (ss < tt) add(ss, tt);
		else add(tt, ss);
	}
	int ans = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = h[i]; ~j; j = ne[j]) st[e[j]] = i;
		for (int j = h[i]; ~j; j = ne[j]) {
			int tt = e[j];
			for (int k = h[tt]; ~k; k = ne[k])
				if (st[e[k]] == i) ans += 1;
		}
	}
	cout << ans << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值