这里的题目一般都是维护状态,每个集合表示的是一种状态(一般为两个)
题目会询问第一次状态冲突的时候[并查集添加状态的时候发现已有状态并且状态不对]
数据结构K题
K题讲述的是:告诉你n个区间的和的奇偶,判断第一个矛盾的地方。
区间和的奇偶可以转换成可以维护的前缀和之差的奇偶,和为奇,前缀和sum[l-1]和sum[r]一定奇偶不同。
前者奇后者偶,或者反过来。这两种状态我们都添加到并查集里去。
那么怎么表示哪个是奇数呢,0~n为奇数,n+1~2*n+1为偶数。类似于罪犯分配问题。后者做过的前提我还没做出来K题,看到题解才恍然大悟,脑子不行就要靠刷题弥补。
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;
const int MAXN = 1000050*2;
int n,m;
int f[MAXN];
struct UnionSet {
UnionSet(int n) {
for (int i = 0; i <= 2*n+1; i++) {
f[i] = i;
}
}
UnionSet(){}
void uni(int x, int y) {
f[find(x)] = find(y);
}
bool query(int x, int y) {
return find(x) == find(y);
}
int find(int x) {
return f[x] == x ? x : (f[x] = find(f[x]));
}
} us;
int main(){
cin>>n>>m;
char ch[10];
us=UnionSet(n);
FOR(i,1,m){
int x,y;
scanf("%d%d%s",&x,&y,ch);
x--;
if(ch[0]=='e'){
if(us.query(x,y+n+1)||us.query(x+n+1,y)){
cout<<i-1<<endl;
return 0;
}
us.uni(x,y);
us.uni(x+n+1,y+n+1);
}
else{
if(us.query(x,y)||us.query(x+n+1,y+n+1)){
cout<<i-1<<endl;
return 0;
}
us.uni(x+n+1,y);
us.uni(x,y+n+1);
}
}
cout<<"ORZQHQH"<<endl;
}