G. Penacony
On Penacony, The Land of the Dreams, there exists $n$ houses and $n$ roads. There exists a road between house $i$ and $i+1$ for all $1 \leq i \leq n-1$ and a road between house $n$ and house $1$. All roads are bidirectional. However, due to the crisis on Penacony, the overseeing family has gone into debt and may not be able to maintain all roads.
There are $m$ pairs of friendships between the residents of Penacony. If the resident living in house $a$ is friends with the resident living in house $b$, there must be a path between houses $a$ and $b$ through maintained roads.
What is the minimum number of roads that must be maintained?
Input
The first line contains $t$ ($1 \leq t \leq 10^4$) – the number of test cases.
The first line of each test case contains two integers $n$ and $m$ ($3 \leq n \leq 2 \cdot 10^5, 1 \leq m \leq 2 \cdot 10^5$) – the number of houses and the number of friendships.
The next $m$ lines contain two integers $a$ and $b$ ($1 \leq a < b \leq n$) – the resident in house $a$ is friends with the resident in house $b$. It is guaranteed all ($a, b$) are distinct.
It is guaranteed the sum of $n$ and $m$ over all test cases does not exceed $2 \cdot 10^5$.
Output
For each test case, output an integer, the minimum number of roads that must be maintained.
Example
Input
7
8 3
1 8
2 7
4 5
13 4
1 13
2 12
3 11
4 10
10 2
2 3
3 4
10 4
3 8
5 10
2 10
4 10
4 1
1 3
5 2
3 5
1 4
5 2
2 5
1 3
Output
4
7
2
7
2
3
3
Note
For the first test case, the following roads must be maintained:
- $8 \leftarrow \rightarrow 1$
- $7 \leftarrow \rightarrow 8$
- $1 \leftarrow \rightarrow 2$
- $4 \leftarrow \rightarrow 5$
解题思路
对于关系 $(a,b)$,最优路径必然是 $a \rightarrow a+1 \rightarrow \dots \rightarrow b$(记为路径 $1$)或 $a \rightarrow a-1 \rightarrow 1 \rightarrow n \rightarrow \dots \rightarrow b$(记为路径 $2$)。这两条路径没有交集,且并集恰好是整个环。
接着有个关键的性质:最优答案必然小于 $n$。反证法,假设最终选择了整个环的 $n$ 条边,现在任选一条边删除,如果某对关系的路径包含这条边,由上述知道必然可以换成该路径的补集。因此在最优解中必然至少有一条边不会被选。为此我们可以枚举每一条边作为不被选择的边。
容易知道在删除环上的一条边后,每对关系的路径都会唯一确定。定义第 $i$ 条边表示连接点 $i$ 和 $i+1$ 之间的边,那么在删除第 $i$ 条边后,如果关系 $(a,b)$ 满足 $a \leq i < b$,则最优路径就是路径 $2$,否则为路径 $1$。显然我们可以枚举每条被删除的边,然后再枚举每对关系把路径标记出来,最后统计被标记的边的数量,取最小值,时间复杂度为 $O(nm)$。
实际上如果从小到大枚举 $i$,当删除第 $i$ 条边时,只有 $a=i$(从路径 $1$ 变路径 $2$)和 $b=i$(从路径 $2$ 变路径 $1$)的关系的路径会受到影响,因此整个过程中只会改变 $2m$ 次路径。如果要标记路径 $1$,则可以对区间 $[a,b)$ 进行 $\pm 1$;如果要标记路径 $2$,则分别对区间 $[1,a)$ 和 $[b,n]$ 进行 $\pm 1$。最后查询的是区间 $[1,n]$ 中有标记的长度总和。【模板】扫描线的线段树可以实现该功能,线段树节点只需维护区间 $[l,r]$ 中的最小值 $\text{mn}$,以及最小值的长度总和 $s$。查询的时候,如果 tr[1].mn == 0
,那么有标记的长度总和就是 n - tr[1].s
;否则是 n
。
AC 代码如下,时间复杂度为 $O(n + m \log{n})$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 5;
vector<int> l[N], r[N];
struct Node {
int l, r, mn, s, add;
}tr[N * 4];
void build(int u, int l, int r) {
tr[u] = {l, r, 0, r - l + 1, 0};
if (l != r) {
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
}
}
void upd(int u, int c) {
tr[u].mn += c;
tr[u].add += c;
}
void pushdown(int u) {
if (!tr[u].add) return;
upd(u << 1, tr[u].add);
upd(u << 1 | 1, tr[u].add);
tr[u].add = 0;
}
void modify(int u, int l, int r, int c) {
if (l > r) return;
if (tr[u].l >= l && tr[u].r <= r) {
upd(u, c);
}
else {
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) modify(u << 1, l, r, c);
if (r >= mid + 1) modify(u << 1 | 1, l, r, c);
tr[u].mn = min(tr[u << 1].mn, tr[u << 1 | 1].mn);
tr[u].s = 0;
if (tr[u << 1].mn == tr[u].mn) tr[u].s += tr[u << 1].s;
if (tr[u << 1 | 1].mn == tr[u].mn) tr[u].s += tr[u << 1 | 1].s;
}
}
void solve() {
int n, m;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
l[i].clear(), r[i].clear();
}
build(1, 1, n);
while (m--) {
int a, b;
scanf("%d %d", &a, &b);
l[a].push_back(b);
r[b].push_back(a);
modify(1, a, b - 1, 1);
}
int ret = n;
for (int i = 1; i <= n; i++) {
for (auto &x : l[i]) {
int a = i, b = x;
modify(1, a, b - 1, -1);
modify(1, 1, a - 1, 1);
modify(1, b, n, 1);
}
for (auto &x : r[i]) {
int a = x, b = i;
modify(1, 1, a - 1, -1);
modify(1, b, n, -1);
modify(1, a, b - 1, 1);
}
ret = min(ret, tr[1].mn ? n : n - tr[1].s);
}
printf("%d\n", ret);
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}
参考资料
Codeforces Round 962 (Div. 3) Editorial:https://codeforces.com/blog/entry/131528
标签:10,路径,house,Penacony,leq,roads,rightarrow From: https://www.cnblogs.com/onlyblues/p/18327187