Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目链接:洛谷 P1955。
题目大意:对于每个提问,给出若干个变量约束条件(等于或不等于),问能否找到一组变量的值,使得满足给出的若干变量约束条件。
题目分析:
对于此题,我们不妨将每个变量 视作一个点,如果存在相等约束关系:,那么显然这两个值就是相等的,因此我们可以考虑将这两个变量 和 放入同一个集合当中。如果约束关系为不相等,那么我们就只需要直接判断两个变量是否处于不同集合,如果已经处于了相同集合,说明情况矛盾。
按照这个思路开展下来,一直到最后,如果也没有出现矛盾的情况,那就说明我们可以得到一组满足条件的值。
这样的一个集合关系我们可以使用并查集来处理,使用并查集的基本「合并」与「查询」操作就可以实现元素与集合的处理。
要注意的是,原始数据范围 太大,我们无法直接建立一个长度 的数组来进行维护,这个时候就需要用到离散化了。
既然选择用离散化,那么本题自然而然就需要离线处理,我们用 来存储输入当中的 ,然后我们用另外一个数组 来接收离散化后的结果,对于离散化后的数据,我们就可以将 排序后,用二分查找进行查找原来的那个数即可。
参考代码:
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e6+5;
int n, t, o;
int a[N], b[N], c[N];
int f[N], map[N<<1];
int find(int x) {
return f[x] == x ? x : f[x] = find(f[x]);
}
int query(int x) {
return lower_bound(map + 1, map + 1 + (n << 1), x) - map;
}
void merge(int x, int y) {
int fx = find(x), fy = find(y);
if (fx != fy) {
f[fx] = fy;
}
}
int main() {
scanf("%d", &t);
while(t--) {
o = 0;
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d%d%d", &a[i], &b[i], &c[i]);
map[(i << 1) - 1] = a[i];
map[i << 1] = b[i];
}
sort(map + 1, map + 1 + (n << 1));
for (int i = 1; i <= n << 1; ++i) {
f[i] = i;
}
for (int i = 1; i <= n; ++i) {
if (c[i] == 1) {
int nx = query(a[i]), ny = query(b[i]);
merge(nx, ny);
}
}
for (int i = 1; i <= n; ++i) {
if (c[i] == 0) {
int nx = query(a[i]), ny = query(b[i]);
if(find(nx) == find(ny)) {
o = 1;
break;
}
}
}
if (o) {
puts("NO");
} else {
puts("YES");
}
}
return 0;
}