并查集——奇偶游戏

写在前面:

对于带权并查集,我们最重要的一个函数就是d函数,d[x]代表到达x的父节点的距离。所以对于带权并查集更新的时候我们一般画图,分别画,a,b及他们的父亲节点的图,然后分fa,fb相同和不同的两种情况。一般我们是询问情况的话,有几种情况就是模几的情况下。分别(d[a]+d[b])%mod是否等于我们a与b的关系然后判断矛盾。mod2的情况的加减运算就是我们的亦或运算。
对于判断关系的并查集我们还可以用拓展域并查集来写,但是有时候关系太多会超时。
接下来以下面的题来写两种方法。

奇偶游戏

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

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

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

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

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

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

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

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

输入格式
第一行包含一个整数N,表示01序列长度。

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

扫描二维码关注公众号,回复: 9017904 查看本文章

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

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

数据范围
N≤109,M≤10000
输入样例:
10
5
1 2 even
3 4 odd
5 6 even
1 6 even
7 10 odd
输出样例:
3

带权并查集:

这里用了前缀和的思想。前缀和数组一定能构造出一个a仅存在01的数组。

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+7;
int s[N],pre[N],d[N];
int find(int x)
{
    if(x!=pre[x]){
        int rt=find(pre[x]);
        d[x]^=d[pre[x]];
        pre[x]=rt;
    }
    return pre[x];
}
//定义d函数d[x]代表x到达根节点的距离
int cnt;
unordered_map<int,int> ma;
int get_hash(int x)
{
    if(!ma.count(x)) ma[x]=++cnt;
    return ma[x];
}
int main()
{
    int n,m; scanf("%d%d",&n,&m);
    for(int i=1;i<=20010;i++) pre[i]=i;
    int res=m;
    for(int i=1;i<=m;i++){
        int a,b;
        string str;
        cin>>a>>b>>str;
        int t=0;
        if(str=="odd") t=1;
        a=get_hash(a-1);
        b=get_hash(b);
        int fx=find(a);
        int fy=find(b);
        if(fx!=fy){
            pre[fx]=fy;
            d[fx]=d[a]^d[b]^t;
        }else{
            if((d[a]^d[b])!=t){
                res=i-1;
                break;
            }
        }
    }
    cout<<res<<endl;
}

拓展域并查集:

拓展域合并的是一个大集合,集合中存在各种关系。只有有一个关系成立,那么这个集合中的所有关系成立,而不像我们的边权并查集是两两之间的关系。

#include <bits/stdc++.h>
using namespace std;
const int N=40020,base=N/2;
int s[N],pre[N],d[N];
int find(int x) {
    if (x != pre[x]) return pre[x] = find(pre[x]);
    return pre[x];
}
int cnt;
unordered_map<int,int> ma;
int get_hash(int x) {
    if (!ma.count(x)) ma[x] = ++cnt;
    return ma[x];
}
int main()
{
    int n,m; scanf("%d%d",&n,&m);
    for(int i=1;i<=40020;i++) pre[i]=i;
    int res=m;
    for(int i=1;i<=m;i++){
        int a,b;
        string str;
        cin>>a>>b>>str;
        a=get_hash(a-1);
        b=get_hash(b);
        if(str=="odd"){
            if(find(a+base)==find(b+base)){
                res=i-1;
                break;
            }
            pre[find(a)]=find(b+base);
            pre[find(a+base)]=find(b);
        }else{
            if(find(a)==find(b+base)){
                res=i-1;
                break;
            }
            pre[find(a)]=find(b);
            pre[find(a+base)]=find(b+base);
        }
    }
    cout<<res<<endl;
}
发布了181 篇原创文章 · 获赞 10 · 访问量 5079

猜你喜欢

转载自blog.csdn.net/weixin_42979819/article/details/104170128
今日推荐