题目链接:https://www.acwing.com/problem/content/description/241/
并查集的一个重要功能就是动态维护具有传递性的关系,
比如:相等,奇偶性等等
如果传递关系只有一种,比如相等,那就使用普通的并查集来维护即可
如果传递关系不只有一种,比如本题的奇偶性:
- 如果 (x_1) 与 (x_2) 奇偶性相同, (x_2) 和 (x_3) 奇偶性相同,则 (x_1) 和 (x_3) 奇偶性相同(与相等关系一样)
- 如果 (x_1) 与 (x_2) 奇偶性相同, (x_2) 和 (x_3) 奇偶性不同,则 (x_1) 和 (x_3) 奇偶性不同
- 如果 (x_1) 与 (x_2) 奇偶性不同, (x_2) 和 (x_3) 奇偶性不同,则 (x_1) 和 (x_3) 奇偶性相同
这时候需要使用边带权的并查集:
令 (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
",i - 1); return 0;
}
} else{
fa[p] = q;
d[p] = d[x] ^ d[y] ^ query[i].ans;
}
}
printf("%d
",m);
return 0;
}