AcWing 239 奇偶游戏 (带权并查集 / 扩展域并查集)
题目链接:https://www.acwing.com/problem/content/description/241/
并查集的一个重要功能就是动态维护具有传递性的关系,
比如:相等,奇偶性等等
如果传递关系只有一种,比如相等,那就使用普通的并查集来维护即可
如果传递关系不只有一种,比如本题的奇偶性:
- 如果 x1 与 x2 奇偶性相同, x2 和 x3 奇偶性相同,则 x1 和 x3 奇偶性相同(与相等关系一样)
- 如果 x1 与 x2 奇偶性相同, x2 和 x3 奇偶性不同,则 x1 和 x3 奇偶性不同
- 如果 x1 与 x2 奇偶性不同, x2 和 x3 奇偶性不同,则 x1 和 x3 奇偶性相同
这时候需要使用边带权的并查集:
令 d[x] 表示 x 与集合的根的奇偶性关系,0 相同,1 不同
在 find 的时候更新 d 即可,合并时也要更新一下
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 30010;
int n, m;
struct Q{
int l, r, ans;
}query[maxn];
char s[10];
int a[maxn], cnt = 0;
int fa[maxn], d[maxn]; // 0 same 1 different
int find(int x){
if(fa[x] == x) return x;
int root = find(fa[x]);
d[x] ^= d[fa[x]];
return fa[x] = root;
}
ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; ++i){
scanf("%d%d%s", &query[i].l, &query[i].r, s);
if(s[0] == 'o') query[i].ans = 1; else query[i].ans = 0;
a[++cnt] = query[i].r, a[++cnt] = query[i].l - 1;
}
sort(a + 1, a + 1 + cnt);
n = unique(a + 1, a + 1 + cnt) - a - 1;
for(int i = 1; i <= n ; ++i) fa[i] = i;
for(int i = 1; i <= m; ++i){
int x = lower_bound(a + 1, a + 1 + n, query[i].l - 1) - a;
int y = lower_bound(a + 1, a + 1 + n, query[i].r) - a;
int p = find(x), q = find(y);
if(p == q) {
if((d[x] ^ d[y]) != query[i].ans){
printf("%d\n",i - 1); return 0;
}
} else{
fa[p] = q;
d[p] = d[x] ^ d[y] ^ query[i].ans;
}
}
printf("%d\n",m);
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步