0115C补充
本文搬运自本人高中时期CSDN博客,若图片加载不出来,可到原文查看:https://blog.csdn.net/zhangtingxiqwq/article/details/135640069
前 : https://blog.csdn.net/zhangtingxiqwq/article/details/135612739
这题的图是和很特殊的图,它是一个竞赛图扣去了 m m m 条边,且剩下的边满足传递封闭性。
在这种情况下,我们每个点暴力往自己可以匹配最小的点去匹配,则最多有 m \sqrt m m 个点无法匹配。(这一步的证明用到了封闭性)
对于这一步的匹配,我们可以用set维护剩余可匹配的点。因为非法边总共就 m m m 条,我们可以类似two-pointers那样筛走。
我们最后对这 m \sqrt m m 跑一次匈牙利算法。正常情况下单个点匈牙利算法是 O ( n 2 ) O(n^2) O ( n 2 ) ,算法的瓶颈在于边数。边不合法有两种情况:
令一个点已经被尝试了
这条边不存在
对于情况2,最多 m m m 条边。对于情况1,我们直接拿并查集维护当前未尝试过的点。因此单个点匈牙利的复杂度是 O ( n log n + m ) O(n\log n+m) O ( n log n + m ) 。而要跑的点不超过 O ( m ) O(\sqrt m) O ( m ) 个,因此宗复杂度为 O ( n log n + m ( n log n + m ) ) O(n\log n+\sqrt m(n\log n+m)) O ( n log n + m ( n log n + m ))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 #include <bits/stdc++.h> using namespace std;#ifdef LOCAL #define debug(...) fprintf(stdout, ##__VA_ARGS__) #else #define debug(...) void(0) #endif inline int read () {int x=0 ,f=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )f=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+ (x<<3 )+(ch^48 );ch=getchar ();}return x*f;} #define Z(x) (x)*(x) #define pb push_back #define fi first #define se second #define N 200010 int n, m, i, j, k, T;int f[N], to[N], shu[N], a[N], ans, vis[N]; vector<int >G[N]; set<int > s; int fa (int x) { if (f[x] == x) return x; return f[x] = fa (f[x]); } int dfs (int x) { int l = 0 ; for (int i = fa (1 ); i < x; i = fa (i + 1 )) { while (l < G[x].size () && G[x][l] < i) ++l; if (l == G[x].size () || G[x][l] != i) { ++f[i]; if (!shu[i] || dfs (shu[i])) return shu[i] = x, to[x] = i, 1 ; } } return 0 ; } signed main () { freopen ("excavator.in" , "r" , stdin); freopen ("excavator.out" , "w" , stdout); n = read (); m = read (); ans = n; for (i = 1 ; i <= n; ++i) a[i] = i; for (i = 1 ; i <= m; ++i) { j = read (); swap (a[j], a[j + 1 ]); G[max (a[j], a[j + 1 ])].pb (min (a[j], a[j + 1 ])); } for (i = 1 ; i <= n; ++i) sort (G[i].begin (), G[i].end ()); for (i = 1 ; i <= n; ++i) { int l = 0 ; for (int j : s) { while (l < G[i].size () && G[i][l] < j) ++l; if (l == G[i].size () || G[i][l] != j) { s.erase (j); to[i] = j; shu[j] = i; --ans; break ; } } s.insert (i); } for (i = 1 ; i <= n; ++i) { if (to[i]) continue ; for (j = 1 ; j <= n; ++j) f[j] = j; ans -= dfs (i); } printf ("%lld" , ans); return 0 ; }