#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
const int N = 5000 + 5;
int p[2*N],n,m;
int left[N], r[2*N], right[N];
char operat[N][5];
map<int, int> Map;
void init() {
for(int i = 0; i <= N; i++) {
p[i] = i;
r[i] = 0;//r为1代表奇数,为0代表偶数
}
return;
}
//带权并查集
int find_p(int x) {
if(p[x] == x)
return x;
int px = p[x];
p[x] = find_p(px);
r[x] = (r[x] + r[px]) % 2;//x的权值更新,是奇数还是偶数
return p[x];
}
bool Union(int x, int y, int d) {//d: 为1代表奇数,为0代表偶数
int px = find_p(x);
int py = find_p(y);
if(px == py) {
if((r[x] - r[y] + 2) % 2 != d)
return false;
return true;
}
//如果u-1与v此时不在同一个分量中,那么我们可以知道(u-1,F[u-1]]区间和(v,F[v]]区间1的属性且我们知道(u-1,v]区间的1属性,那么我们可以推算出(F[u-1],F[v]](假设F[u-1]<F[v])区间的属性,进而合并F[u-1]与F[v]的连通分量
if(px < py) {//合并两个连通分量的时候,我们始终保持编号大的节点作为父亲,编号小的节点作为儿子
p[px] = py;
r[px] = (r[y] - r[x] + d + 2) % 2;//key point:
} else {
p[py] = px;
r[py] = (r[x] - r[y] - d + 4) % 2;//key point:
}
return true;
}
int main() {
freopen("data.in", "r", stdin);
while(scanf("%d%d",&n,&m) == 2) {
Map.clear();
int pos = 1;
init();
for(int i = 0; i < m; i++) {
scanf("%d %d %s", &left[i], &right[i], operat[i]);
//离散化,重新映射到数轴上
//预先读入所有输入数据对(u,v)且存储(u-1,),然后将所有的u-1和v排序重新从1到X编号(即用map重新映射到数轴上)
if(!Map[left[i] - 1])
Map[left[i] - 1] = pos++;
if(!Map[right[i]])
Map[right[i]] = pos++;
}
int i;
for(i = 0; i < m; i++) {
if(operat[i][0] == 'e') {//偶数
if(!Union(Map[left[i] - 1], Map[right[i]], 0))
break;
} else {//奇数
if(!Union(Map[left[i] - 1], Map[right[i]], 1))
break;
}
}
printf("%d\n", i);
}
}
POJ 1733 Parity game(带权并查集+离散化)
最新推荐文章于 2022-05-04 09:09:58 发布