并查集-POJ1733Parity game

来源:互联网 发布:爱动体感运动机 知乎 编辑:程序博客网 时间:2024/06/07 06:31

http://poj.org/problem?id=1733
首先感谢一下poj,讨论里面数据都有;
全英文题目根本无版权问题
不像某谷省选题数据不给的;
这道题就是并查集;
给你x,y的区间,让这个区间1的数量是奇数偶数;
这道题目我做了大约两个小时;
唉~~~~
但是毕竟是自己做出来的;
我们并查集,可以记录1~x的数的奇偶性;
然后就用拆点嘛,和监狱那题差不多;
然后就没了;
……………
当然我也算是从最原始的并查集里面走出来了;
不是拆点嘛;
我一开始拆成偶数奇数,然后就下不去了;
后来才想到要拆成相同不相同;
显然把,相同不相同才可以把题目转换成集合;
而偶数奇数只有两个集合;
离散就不讲了;
自己搞吧;
反正因为我的并查集记录的是1~x的区间;
所以我们对于一个区间x,y要算1~x-1,1~y两个区间;
呵呵呵呵,所以离散就要判断两个数是否相差1;
当然,建议大家把最小的值设为2而不是1;
为什么?
看我程序把,我是设为1 的;

#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>using namespace std;struct cs{    int x,y,z;}F[1000001];int fa[1000001],c[100001][5];int ff,n,m,x,y,z,nn,xx,yy,xxx,yyy;string s;bool cmp(cs x,cs y){return x.z<y.z;}int get(int x){    if(fa[x]==x)return x;    fa[x]=get(fa[x]);    return fa[x];}void merge(int x,int y){fa[get(x)]=get(y);}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++){        scanf("%d%d",&x,&y);        cin>>s;        c[i][1]=x;        c[i][2]=y;        if(s=="odd")c[i][3]=1;        F[++ff].z=x;F[ff].x=i;F[ff].y=1;        F[++ff].z=y;F[ff].x=i;F[ff].y=2;    }    sort(F+1,F+ff+1,cmp);    for(int i=1;i<=ff;i++){        if(F[i].z!=F[i-1].z){            nn++;            if(F[i].z!=F[i-1].z+1)nn++;//离散要保证区间的准确         }        c[F[i].x][F[i].y]=nn;    }//  for(int i=1;i<=m;i++)cout<<c[i][1]<<' '<<c[i][2]<<endl;    for(int i=1;i<=nn*2+2;i++)fa[i]=i;    for(int i=1;i<=m;i++){        x=c[i][1];        y=c[i][2];        z=c[i][3];        xx=get(x-1);        yy=get(y);        xxx=get(x-1+nn+1);        //因为我把最小值设成1,所以x=1时会取到x-1=0;0+nn=nn;所以0和nn会重复!!!!所以我们把区间大小+1,即nn+1;         yyy=get(y+nn+1);        if(z)if(xx==yy||xxx==yyy){printf("%d",i-1);return 0;}else merge(xxx,yy),merge(yyy,xx);        if(!z)if(xx==yyy||yy==xxx){printf("%d",i-1);return 0;}else merge(xx,yy),merge(xxx,yyy);    }    printf("%d",m);}
1 0