POJ 1733 Parity game 【带权并查集】+【离散化】

时间:2021-12-16 08:13:22

<题目链接>

题目大意:

一个由0,1组成的序列,每次给出一段区间的奇偶,问哪一条信息不合法。

解题分析:

我们用s[i]表示前i个数的前缀和,那么a b even意味着s[b]和s[a-1]的奇偶性相同。a b odd意味着s[b]与s[a-1]的奇偶性不同。于是我们根据奇偶性的不同,用并查集依次处理他们之间的关系。当某条信息出现与并查集中记录的信息不符合时,则此信息不合法。

由于该序列的长度达到了1e9,并且查询次数只有5000次,所以我们需要对查询的区间进行离散化,否则存不下,数据比较小,用map离散化即可,也不会很慢。

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
using namespace std; #define RP(i,s,t) for(int i=s;i<=t;i++)
#define fastIO ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
const int N = 1e4 + ; int n, m, tot,fa[N + ], w[N + ];
map<int,int>mp; int find(int x){
if(x==fa[x])return x;
int tmp=fa[x];
fa[x]=find(fa[x]);
w[x]=(w[x]+w[tmp]+)%; //带权并查集关系的转移
return fa[x];
}
inline bool Union(int a,int b,int x){
int ra=find(a),rb=find(b);
if(ra!=rb){
fa[ra]=rb;
w[ra]=(w[a]-w[b]+x+)%;
}else{
if((w[a]-w[b]+)%!=x)return false; //与之前建立的关系奇偶性不符,则表示出现冲突
}return true;
}
int main() {
fastIO
cin >> n >> m;
RP(i, , N + ) fa[i] = i, w[i] = ;
int ans=;
RP(i,,m){
int a,b;string s;
cin>>a>>b>>s;--a; //因为根据的是前缀和的奇偶性,所以这里a要记得-1
if(!mp[a])mp[a]=++tot; //map用来离散化
if(!mp[b])mp[b]=++tot;
int k=(s=="odd")?:; //odd才是奇,容易搞错
if(Union(mp[a],mp[b],k))ans++;
else break;
}cout<<ans<<'\n';
}

2018-10-02