0115C补充

本文搬运自本人高中时期CSDN博客,若图片加载不出来,可到原文查看:https://blog.csdn.net/zhangtingxiqwq/article/details/135640069

前 : https://blog.csdn.net/zhangtingxiqwq/article/details/135612739

这题的图是和很特殊的图,它是一个竞赛图扣去了 mm 条边,且剩下的边满足传递封闭性。

在这种情况下,我们每个点暴力往自己可以匹配最小的点去匹配,则最多有 m\sqrt m 个点无法匹配。(这一步的证明用到了封闭性)

对于这一步的匹配,我们可以用set维护剩余可匹配的点。因为非法边总共就 mm 条,我们可以类似two-pointers那样筛走。

我们最后对这 m\sqrt m 跑一次匈牙利算法。正常情况下单个点匈牙利算法是 O(n2)O(n^2) ,算法的瓶颈在于边数。边不合法有两种情况:

  1. 令一个点已经被尝试了

  2. 这条边不存在

对于情况2,最多 mm 条边。对于情况1,我们直接拿并查集维护当前未尝试过的点。因此单个点匈牙利的复杂度是 O(nlogn+m)O(n\log n+m) 。而要跑的点不超过 O(m)O(\sqrt m) 个,因此宗复杂度为 O(nlogn+m(nlogn+m))O(n\log n+\sqrt 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
//#define int long long
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 M
//#define mo
#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) {
// if(vis[x]) return 0; vis[x] = 1;
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]; // = i + 1;
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);
// srand(time(NULL));
// T=read();
// while(T--) {
//
// }
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;
// memset(vis, 0, sizeof(vis));
for(j = 1; j <= n; ++j) f[j] = j;
ans -= dfs(i);
}
printf("%lld", ans);
return 0;
}