AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AcWing 239. $\Large\color{blue}{【算法提高课】奇偶游戏(离散化+带权并查集)}$    原题链接    中等

作者: 作者的头像   incra ,  2022-11-27 07:49:23 ,  所有人可见 ,  阅读 2012


39


2

<—点个赞吧QwQ

宣传一下算法提高课整理{:target=”_blank”}

小 $A$ 和小 $B$ 在玩一个游戏。

首先,小 $A$ 写了一个由 $0$ 和 $1$ 组成的序列 $S$,长度为 $N$。

然后,小 $B$ 向小 $A$ 提出了 $M$ 个问题。

在每个问题中,小 $B$ 指定两个数 $l$ 和 $r$,小 $A$ 回答 $S[l \sim r]$ 中有奇数个 $1$ 还是偶数个 $1$。

机智的小 $B$ 发现小 $A$ 有可能在撒谎。

例如,小 $A$ 曾经回答过 $S[1 \sim 3]$ 中有奇数个 $1$,$S[4 \sim 6]$ 中有偶数个 $1$,现在又回答 $S[1 \sim 6]$ 中有偶数个 $1$,显然这是自相矛盾的。

请你帮助小 $B$ 检查这 $M$ 个答案,并指出在至少多少个回答之后可以确定小 $A$ 一定在撒谎。

即求出一个最小的 $k$,使得 $01$ 序列 $S$ 满足第 $1 \sim k$ 个回答,但不满足第 $1 \sim k+1$ 个回答。

输入格式

第一行包含一个整数 $N$,表示 $01$ 序列长度。

第二行包含一个整数 $M$,表示问题数量。

接下来 $M$ 行,每行包含一组问答:两个整数 $l$ 和 $r$,以及回答 even 或 odd,用以描述 $S[l \sim r]$ 中有偶数个 $1$ 还是奇数个 $1$。

输出格式

输出一个整数 $k$,表示 $01$ 序列满足第 $1 \sim k$ 个回答,但不满足第 $1 \sim k+1$ 个回答,如果 $01$ 序列满足所有回答,则输出问题总数量。

数据范围

$N \le 10^9 , M \le 5000$

输入样例:

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

输出样例:

3

思路

这是一题带权并查集的题。
观察数据可发现要离散化,我们直接用一个$map$记录一下就好了。
重点是怎么算权值。
在$find$函数后的距离数组表示当前点到根的距离。
所以如果有两个点$x,y$,他们的距离是$s$,那么就像下图一样合并即可:

无标题.png

因为$y$通过两个位置来计算的结果是一样的,所以得出结论:$d[ry]=d[rx]+(s==odd)-d[y]$
在实际计算中,我们可以在最后取模。

代码

#include <iostream>
#include <unordered_map>
using namespace std;
const int N = 10010;
int n,m;
int p[N],d[N];
unordered_map <int,int> mp;
int get (int x) {
    if (!mp.count (x)) mp[x] = ++n;
    return mp[x];
}
int find (int x) {
    if (p[x] != x) {
        int rx = find (p[x]);
        d[x] += d[p[x]];
        p[x] = rx;
    }
    return p[x];
}
int main () {
    cin >> m >> m;  //n没啥用,都要离散化的
    for (int i = 1;i < N;i++) p[i] = i;
    int ans = m;
    for (int i = 1;i <= m;i++) {
        int x,y;
        string s;
        cin >> x >> y >> s;
        x = get (x - 1),y = get (y);    //这里是为了变成左开右闭的区间,因为x是要保留的,因为一减就会减掉当前数
        int rx = find (x),ry = find (y);
        int t = s == "odd";
        if (rx == ry && abs (d[x] - d[y]) % 2 != t) {
            ans = i - 1;
            break;
        }
        else if (rx != ry) {
            p[ry] = rx;
            d[ry] = abs (d[x] - d[y] - t);
        }
    }
    cout << ans << endl;
    return 0;
}

5 评论


用户头像
user.banned   2024-01-21 17:02      1    踩      回复

umap怎么没被卡

用户头像
incra   2024-01-21 18:14      1    踩      回复

because AcWing != CF


用户头像
acwing_xyy   2023-05-03 16:23      1    踩      回复

把d[x] += d[p[x]]改成d[x] ^= d[p[x]]会好些

用户头像
incra   2023-05-03 17:09      1    踩      回复

也可以,等价于d[x] = d[x] + d[p[x]] & 1


用户头像
甲乙_6   2024-04-25 10:22         踩      回复

这里的并查集在路径压缩的时候不改变奇偶性质,有点难想QAQ


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息