TIOJ-2146

給定$N, M$,求一張滿足所有$M$筆條件(點$i$最後要到點$j$)且有$N$條縱線的鬼腳圖最少需要幾條橫線。

$N\le 10^5, M\le N$


這問題好難>< 問別人才會。
定義$p$數列為$p_i$代表$i$最後會走到$p_i$,無任何橫線時$p_i=i$。

考慮以下greedy策略:由最底層不斷往上加橫線,此時在$(i, i+1)$間加一條橫線等價於交換$(p_i,p_{i+1})$。
這樣就能知道,如果要讓$p$變成題目要求,等價於將題目要求進行泡沫排序,所以至少要交換逆序數對次。
至於題目未指定的條件,則將$1\sim N$分別指定給他們,這樣逆序數對數量會最少。

逆序數對可用BIT或Merge sort處理,時間複雜度$\mathcal{O}(NlogN)$。

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
/*
-------------- | /
| | /
| | /
| * |/ | | ------ *
| | | | / \
| | |\ | | | |\ |
\ | | | \ | | | | \ |
\ | | | \ | | \ / \ |
V | | \ \__/| ----- \ |
*/
#include <bits/stdc++.h>
using namespace std;

#define EmiliaMyWife ios::sync_with_stdio(0); cin.tie(NULL);
using ll = int64_t;
/*-----------------------------------------------------------------------------------------------------*/

const int N = 5e5+25;
ll bit[N];
void mod(int p, int val) {
for(; p<N; p+=p&-p)
bit[p] += val;
}
ll sum(int p) {
ll res = 0;
for(; p; p-=p&-p)
res += bit[p];
return res;
}

signed main() {
EmiliaMyWife

int n, m;
cin >> n >> m;
vector<int> arr(n+1), vis(n+1);
for(int i = 1, a, b; i <= m; i++)
cin >> a >> b, arr[a] = b, vis[b] = 1;
int it = 1;
for(int i = 1; i <= n; i++) {
if(arr[i])
continue;
while(vis[it])
it++;
arr[i] = it++;
}
ll ans = 0;
for(int i = 1; i <= n; i++) {
ans += sum(n)-sum(arr[i]);
mod(arr[i], 1);
}
cout << ans << '\n';

return 0;
}