原题传送门
这题我用并查集过了
看到范围1e9,所以先离散
然后每次把点对应的两个时间用并查集连条边
对于每个点的两个时间,分类讨论
- 两个时间都没选,暂时选小的那个,并用并查集把两个时间连起来
- 有一个选了,那么这次选剩下的那个,然后把这两个时间删掉(就是在并查集里把他们的祖先设置为0)
- 都选过了(表现为两个时间的祖先都为0),那么直接输出-1得了
为什么这题用并查集就搞定了呢,并查集的连边操作的意义是什么?
其实感性理解一下就行了
以
(
1
,
5
)
(
1
,
7
)
(
5
,
13
)
(1,5)(1,7)(5,13)
(1,5)(1,7)(5,13)为例
对于第一个任务,我先选了1,把1与5连起来,并且5是1的祖先;
对于第二个任务,我的待选时间就变为了
(
5
,
7
)
(5,7)
(5,7),那么我选5的意义是:对于第一个任务选1的操作反悔,改选5,然后我在第二个任务的时候选择了1
这就是并查集在这里的用处
具体实现在代码更好
Code:
#include <bits/stdc++.h>
#define maxn 1000010
using namespace std;
struct node{
int id, x, v;
}a[maxn << 1];
int n, ans, num[maxn << 1], f[maxn << 1], p;
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
bool cmp1(node x, node y){ return x.x < y.x; }
bool cmp2(node x, node y){ return x.id == y.id ? x.v < y.v : x.id < y.id; }
int get(int k){ return k == f[k] ? k : f[k] = get(f[k]); }
int main(){
n = read();
for (int i = 1; i <= n; ++i) a[(i << 1) - 1].x = read(), a[i << 1].x = read(), a[(i << 1) - 1].id = a[i << 1].id = i;
sort(a + 1, a + 1 + (n << 1), cmp1);
a[0].x = a[1].x + 1;
for (int i = 1; i <= (n << 1); ++i) a[i].v = a[i].x == a[i - 1].x ? p : ++p, num[a[i].v] = a[i].x;
sort(a + 1, a + 1 + (n << 1), cmp2);
for (int i = 1; i <= p; ++i) f[i] = i;
for (int i = 1; i <= n; ++i){
int s1 = get(a[(i << 1) - 1].v), s2 = get(a[i << 1].v);
if (!s1 && !s2){ puts("-1"); return 0; }
if (s1 == s2 || !s1 || !s2){ ans = max(ans, max(num[s1], num[s2])); f[s1] = f[s2] = 0; } else{
if (s1 > s2) swap(s1, s2);
ans = max(ans, num[s1]); f[s1] = s2;
}
}
printf("%d\n", ans);
return 0;
}

本文介绍了一种使用并查集数据结构解决特定时间选择问题的方法。通过离散化和并查集的连边操作,实现了对多个任务中时间的选择与调整,确保了每个任务至少选择一个时间点,避免重复选择同一时间点。文章提供了详细的代码实现,展示了并查集在处理此类问题上的高效性和灵活性。
3133

被折叠的 条评论
为什么被折叠?



