算法竞赛进阶指南---0x41(并查集)Parity game

题面

在这里插入图片描述

输入样例

10
5
1 2 even
3 4 odd
5 6 even
1 6 even
7 10 odd

输出样例

3

题解

  1. 嗯。。。。想不出来什么引导过程,直接上题解吧,我们先来推导一个性质,设Si 表示前i个数中1的个数,那么设 S[l,r] 中 有奇数个1 ,我们就可以推出Sr 与 Sl-1 的奇偶性不同。这个应该很好理解吧,就是不论一个数是奇数还是偶数,加上一个奇数,就会变(奇+奇=偶,偶+奇=奇),这样我们就将区间的奇偶转化成了两个边界的奇偶,当然这里是l-1和r 之间的奇偶关系
  1. 现在我们就只需要来维护点与点之间的关系,点与点之间只有三种关系(奇,偶,没关系),对于没关系的点,我们就放在集合中维护,对于有关系的点,我们就进行判断是否正确,那么怎样判断呢,,我们可以维护点到根节点的距离,用带边权的并查集就可以了。
  1. 判断操作:对于给定的两个数,如果在同一个集合中,我们看a,b 两点到根节点的距离之和的奇偶是否和输入的相同
    在这里插入图片描述
  2. 合并操作:对于根节点不在同一个集合中的两个数,我们就将他们合并,图中将a 的祖宗节点合并到b的祖宗节点上,要想使ab的奇偶关系不变,那么就要维护ab到新的祖宗节点pb的距离,如果题中输入的ab奇偶性不同的话,那么ab到pb的距离之和就应该为奇数,那么就可以算出d[pa] 的距离,奇数可以取任意奇数值。
    在这里插入图片描述
  1. 题中的值较大,但是个数相对较少,所以在操作之前先离散化一下

代码

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<unordered_map>

using namespace std;
const int N = 2e4 + 10;

int n, m;
unordered_map<int, int> mp;
int p[N], d[N];


//离散化
int get(int x) {
    
    
    if (mp.count(x) == 0) mp[x] = ++n;
    return mp[x];
}

//初始化并查集
void init() {
    
    
    for (int i = 1; i < N; i++) {
    
    
        p[i] = i;
        d[i] = 0;
    }
}

//并查集查找
int find(int x) {
    
    
    if (p[x] != x) {
    
    
        int root = find(p[x]);
        d[x] += d[p[x]];
        p[x] = root;
    }
    return p[x];
}


int main() {
    
    

    init();
    cin >> n >> m;
    n = 0;
    int res = m;
    for (int i = 1; i <= m; i++) {
    
    
        int a, b;
        string type;
        cin >> a >> b >> type;
        a = get(a - 1), b = get(b);
        int pa = find(a), pb = find(b);
        if (pa == pb) {
    
    
            if (type == "odd") {
    
    
                if (!(abs(d[a] + d[b]) & 1)) {
    
    
                    res = i - 1;
                    break;
                }
            } else {
    
    
                if (abs(d[a] + d[b] & 1)) {
    
    
                    res = i - 1;
                    break;
                }
            }
        } else {
    
    
            if (type == "odd") {
    
    
                p[pa] = pb;
                d[pa] = 1 - d[a] - d[b];
            } else {
    
    
                p[pa] = pb;
                d[pa] = -d[a] - d[b];
            }
        }
    }
    cout << res << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44791484/article/details/113825505
今日推荐