Parity game POJ

题意:现在有一个长度为n的零一串,给出m次查询,每次查询格式为:从第u位到第v位的1的个数为奇数或者偶数,其中
“even” 是偶数的意思“odd” 是奇数的意思。问,前几个查询是正确的,也就是第一个错误的查询的前一条查询是第几次查询。


    思路:带权并查集,权值为  本节点到父亲节点的1的个数的奇偶性,偶数为0,奇数为1,由于n很大,我们开不了这么大的数组,但是m只有5000,所以我们考虑压缩一下。  看代码操作

#include<iostream>
#include<map>
#include<cstring>
using namespace std;
const int Max=10005;
struct node//记录父亲节点和权值
{
    int par,relation;
};
node p[Max];
map<int ,int > mmp;//数据比较大,所以用map压缩
int n,m,cnt,ans,flag;
void init()
{
    flag=cnt=0;
    mmp.clear();
    for(int i=1;i<Max;i++){
        p[i].par=i;
        p[i].relation=0;
    }
}
int Hash(int x)//hash,压缩函数
{
    if(mmp.find(x)==mmp.end())//对应数字出现的顺序,由于查询只有5000次,所最多会出现10000个数字
    mmp[x]=cnt++;             //这样就将1e9的数据压缩到了1e5的范围里面
    return mmp[x];
}
int Find(int x)//查找函数
{
    if(x==p[x].par)
        return x;
    int tmp=p[x].par;
    p[x].par=Find(tmp);
    p[x].relation^=p[tmp].relation;//权值的转移
    return p[x].par;
}
bool unite(int x,int y,int c)
{
    int root1=Find(x);
    int root2=Find(y);
    if(root1!=root2){//根不同,将y的根连到x的根上面
        p[root2].par=root1;
        p[root2].relation=c^p[x].relation^p[y].relation;//权值的转移
    }
    else{//根相同则直接判断是否正确
        if(c!=p[x].relation^p[y].relation)
            return 0;
    }
    return 1;
}
int main()
{
    int u,v,tmp;
    char str[10];
    while(cin>>n>>m){
        init();
        for(int i=0;i<m;i++){
            cin>>u>>v>>str;
            if(u>v) swap(u,v);;
            u=Hash(u-1);
            v=Hash(v);
            if(str[0]=='e') tmp=0;
            else tmp=1;
            if(!flag&&!unite(u,v,tmp)){
                    ans=i;
                    flag=1;
            }
        }
        if(!flag)//需要注意的是,如果所有的查询都正确,那么直接输出查询的次数即可
            cout<<m<<endl;
        else
            cout<<ans<<endl;
    }
    return 0;
}


原文地址:https://www.cnblogs.com/Levi-0514/p/9092863.html