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

<题目链接>

题目大意:

一个由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 + 5;

int n, m, tot,fa[N + 10], w[N + 10];
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]+2)%2;         //带权并查集关系的转移
  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+2)%2;
  }else{
    if((w[a]-w[b]+2)%2!=x)return false;            //与之前建立的关系奇偶性不符,则表示出现冲突 
  }return true;
}
int main() {
  fastIO
  cin >> n >> m;
  RP(i, 1, N + 5) fa[i] = i, w[i] = 0;
  int ans=0;
  RP(i,1,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")?1:0;                        //odd才是奇,容易搞错 
    if(Union(mp[a],mp[b],k))ans++;
    else break;
  }cout<<ans<<'
';
}

2018-10-02

原文地址:https://www.cnblogs.com/00isok/p/9738887.html