Codeforces Round 600 (Div. 2) - D. Harmonious Graph

Link: D. Harmonious Graph

D. Harmonious Graph
Description: You're given an undirected graph with n nodes and m edges. Nodes are numbered from 1 to n.

The graph is considered harmonious if and only if the following property holds:

For every triple of integers (l,m,r) such that 1≤l<m<r≤n, if there exists a path going from node l to node r, then there exists a path going from node l to node m.
In other words, in a harmonious graph, if from a node l we can reach a node r through edges (l<r), then we should able to reach nodes (l+1),(l+2),…,(r−1) too.

What is the minimum number of edges we need to add to make the graph harmonious?

Input
The first line contains two integers n and m (3≤n≤200 000 and 1≤m≤200 000).

The i-th of the next m lines contains two integers ui and vi (1≤ui,vi≤n, ui≠vi), that mean that there's an edge between nodes u and v.

It is guaranteed that the given graph is simple (there is no self-loop, and there is at most one edge between every pair of nodes).

Output
Print the minimum number of edges we have to add to the graph to make it harmonious.

Examples
input
14 8
1 2
2 7
3 4
6 3
5 7
3 8
6 8
11 12
output
1
input
200000 3
7 9
9 8
4 5
output
0
Note
In the first example, the given graph is not harmonious (for instance, 1<6<7, node 1 can reach node 7 through the path 1→2→7, but node 1 can't reach node 6). However adding the edge (2,4) is sufficient to make it harmonious.

In the second example, the given graph is already harmonious.

Problem solving:
这道题的意思是给你一张图可能是不连通的图。每个顶点都有一个编号。规定一种特殊的图:这个图中如果从顶点i可以到达顶点j,并且如果存在一个数k(i<k<j),那么i也应该可以到达k。现在给你一个图,问你至少需要再加几条边可以让这个图变成规定的那种特殊的图。

一开始毫无思路,最后还是靠bly过了这道题。吹爆bly。
我们通过并查集把输入的有边的顶点连在一起,此时父节点是同一个顶点的点是可以相互到达的。
我们每次都让最小的顶点做一个连通块的父节点。首先对一个中间变量赋值为节点n的父节点,然后从n开始遍历每一个顶点,如果当前顶点的值小于那个中间变量,说明他和上一个连通块没有关系。就对mid的值进行更新。然后如果出现i>=mid的情况,就看这个节点的父节点跟不跟mid相等,如果不相等就连一条边连起来,答案加一。然后更新一下mid的最小值,因为我们一直是以最小的点作为父节点。

Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int       f[maxn];
int find(int x)
{
    return f[x] != x ? f[x] = find(f[x]) : x;
}
void join(int x, int y)
{
    x = find(x), y = find(y);
    if (x != y)
    {
        if (x < y)
            swap(x, y);
        f[x] = y;
    }
}
int main()
{
    ios::sync_with_stdio(0);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        f[i] = i;
    for (int i = 0, u, v; i < m; i++)
    {
        cin >> u >> v;
        join(u, v);
    }
    int ans = 0, mid = find(n);
    for (int i = n; i >= 1; i--)
    {
        if (i < mid)
            mid = find(i);
        else if (find(i) != mid)
            join(i, mid), ans++;
        mid = min(find(i), mid);
    }
    cout << ans << endl;
    return 0;
}
全部评论

相关推荐

今天 11:02
已编辑
北方民族大学 全栈开发
“无名小卒,还是名扬天下?”我知道很多人都不觉得我能走到今天这一步,当然,也包括我自己。在我的人生里,有两部作品刻下了最深的烙印:《斗破苍穹》与《龙族》。它们总被人拿来对照:一边是萧炎的桀骜轻狂,一边是路明非的怯懦衰颓。有人说,天蚕土豆没见过魂天帝,但江南见过真凯撒。我时常觉得,自己就是那个衰小孩路明非。可路明非可以开挂,我不可以;我也无数次幻想过,能拥有萧炎那般年少轻狂的人生,可我没有他与生俱来的逆天天赋。我只是个平庸的普通人,一个看过《斗破苍穹》却开不了挂的路明非,只能一步一步往上爬。从我下定决心找实习的那一刻起,我就给自己定下了目标:“我一定要为字节跳动卖命.jpg”。萧炎有他的三年之约,我有我的两年半之约(其实是一年半)。2024.11.20,科大讯飞的第一封实习offer落进邮箱,我迈出了这场奔赴的第一步。2025.8.18,放弃百度转正的安稳机会,转身走进前路未卜的不确定里。我很感谢我在百度的mentor,是她从茫茫人海选中了我,给了我大厂实习的机会。即便有段时间我状态差、产出不理想,她依旧愿意认可我、希望我留下转正。2025.11.14,我选择走进字节跳动,以实习生的身份重新出发。2026.3.25&nbsp;-&nbsp;3.31,一周速通上海飞书,幸遇赏识我的伯乐,斩获Special&nbsp;Offer。被告知面试通过的那一刻,我的内心无比平静,就像这个offer本就该属于我。不是侥幸,是应得的。这一路,有人看轻过我的出身,不相信我能走到这里;也有人在我看不见前路的时候,替我举过灯。没有他们的鼓励与支撑,就没有今天站在这里的我。我看到了自强不息的激荡,那是一个双非的伟大乐章!我是雨夜迈巴赫,我要开启属于我的新篇章了。
在看牛客的本杰明很勇...:真心祝贺l总 我永远的偶像 我滴神
春招至今,你收到几个面试...
点赞 评论 收藏
分享
02-28 13:25
已编辑
门头沟学院 Java
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务