https://www.luogu.com.cn/problem/P1989
经典问题,
对于原图的每一条边u?>vu->vu?>v,如两点的度数不一样,那么就度数小的连向度数大的,否则编号小的连向编号大的
然后考虑新图的每一条边u?>vu->vu?>v遍历和vvv相连的每个点www,看www是否和uuu相连,不难发现这个的时间复杂度是∑out[vi]\sum out[v_i]∑out[vi?]的
那么如何证明这个时间复杂度是O(mm)O(m\sqrt{m})O(mm?)的呢?
考虑原图的一个点uuu,如果deg[u]≤mdeg[u]\le \sqrt{m}deg[u]≤m?,显然出度≤m\le \sqrt{m}≤m?
如果deg[u]>mdeg[u]>\sqrt{m}deg[u]>m?,因为只能向度数比uuu大的点vvv连边,然而vvv的个数显然是不超过m\sqrt{m}m?个的,所以显然正确
code:
#include<bits/stdc++.h>
#define N 2000050
using namespace std;
int n, m, in[N], vis[N];
vector<int> g[N];
struct E {
int u, v;
} e[N << 1];
int main() {
scanf("%d%d", &n, &m);for(int i = 1; i <= m; i ++) {
scanf("%d%d", &e[i].u, &e[i].v);in[e[i].u] ++, in[e[i].v] ++;}for(int i = 1; i <= m ; i++) {
int u = e[i].u, v = e[i].v;if(in[u] > in[v]) swap(u, v);if((in[u] == in[v]) && u > v) swap(u, v);g[u].push_back(v);}int ans = 0;for(int u = 1; u <= n; u ++) {
for(int v : g[u]) vis[v] = u;for(int v : g[u])for(int w : g[v])if(vis[w] == u) ans ++;}printf("%d", ans);return 0;
}