acwing 奇偶游戏

题解:用并查集处理到队头1数量的奇偶性,每次合并时候处理,具有传递性,合并ab的时候,找到a的祖先节点pa,pa到b的奇偶性不能直接得出,但能由a到b的奇偶性和a到pa的奇偶性得出,比如a到pb为偶,a到b为偶,得出a到b为偶。再由pa到b和b到pb得出pa到pb奇偶性。

#include<bits/stdc++.h>
using namespace std;
unordered_map<int,int> Hash;
const int N=20010;
int p[N];
int idx;
int d[N];
int ans;
int get(int x)  //离散化
{
    if(!Hash.count(x)) Hash[x]=++idx;
    return Hash[x];
}
int find(int x)
{
    if(p[x]!=x)
    {
        int root=find(p[x]);
        d[x]=d[x]^d[p[x]]; //我到队头的奇偶性由我到当前队头奇偶性和当前队头的奇偶性得出
        p[x]=root;
    }
    return p[x];
}
int main()
{
    for(int i=0;i<N;i++) p[i]=i;
    int n,m;
    cin>>n>>m;
    ans=m;
    for(int i=1;i<=m;i++)
    {
        int a,b;
        string s;
        cin>>a>>b>>s;
        a=get(a-1);          //前缀和思想
        b=get(b);
        int pa=find(a),pb=find(b);
        int t=0;
        if(s=="odd"){
            t=1;
        }
        if(pa!=pb)
        {
            p[pa] = pb;
            d[pa] = d[a] ^ d[b] ^ t;  //合并,pa到队头的奇偶性由a和b,b到队头的奇偶性得出
        }
        if (pa == pb) {
            if ((d[a] ^ d[b]) != t) {  //如果在同一队列,而且二者当前关系和条件不符,矛盾
                ans = i - 1;
                break;
            }
        }
    }
    cout<<ans<<endl;
}

拓展域写法:就是枚举a-1和b前缀和为奇偶的情况去判断。

#include<bits/stdc++.h>
using namespace std;
unordered_map<int,int>M;
const int N=20010;
int p[N*2];
int d[N*2];
int n;
int get(int x)
{
    if(!M.count(x)){
        M[x]=n++;
    }
    return M[x];
}
int find(int x){
    if(p[x]!=x){
        p[x]=find(p[x]);
    }
    return p[x];
}

int main()
{
    int m;
    cin>>n>>m;
    n=0;
    int ans=m;
    for(int i=0;i<N*2;i++) p[i]=i;
    for(int i=0;i<m;i++)
    {
        int a,b;
        string s;
        cin>>a>>b>>s;
        a=get(a-1);
        b=get(b);
        int pa=find(a);           //pa为奇数 ppb枚举为偶数
        int ppa=find(a+N);  
        int pb=find(b);
        int ppb=find(b+N);
        if(s=="even"){           //如果a-1和b之前的数量为偶数,那么他们的奇偶不能在同一并查集中
            if(p[pa]==p[ppb]){
                ans=i;
                break;
            }
            p[pa]=p[pb];   //偶数的情况,那么他们的枚举奇偶时都要一样,合并
            p[ppa]=p[ppb];
        }
        else{
            if(p[pa]==p[pb]){
                ans=i;
                break;
            }
            p[pa]=p[ppb];
            p[ppa]=p[pb];
        }
    }
    cout<<ans<<endl;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值