POJ 1733 Party Game(加权并查集+hash)

来源:互联网 发布:处理器优化 编辑:程序博客网 时间:2024/06/08 16:49

题目链接:
POJ 1733 Party Game
题意:
有n个数字,每个数字非0即1,有m条语句,每条语句:l,r,even/odd,表示l到r区间上有奇/偶个1.
问最多前多少条语句是正确的?
分析:
和POJ 3038 How many answers are wrong? http://acm.hdu.edu.cn/showproblem.php?pid=3038 类似。
用val[i]表示从i到根节点路径上含有1的数量的奇偶性。在寻找根节点的同时更新路径上的val。
比较麻烦的是数据范围。n<=1000000000,而m<=5000.
①:可以用map来标记各个读入点的次序,相当于有个代号,在map里没读入的话就添加进map
在find()和mix()函数里相当于是对代号的操作,代号具有唯一性。
由于m<=5000,所以最多会读入10000个相异的数,那么对于pre数组和val数组都是可以接受的了。
②:hash思路。同样是代号的想法,把l(或r) mod maxn 值相同的归在一类,
用head数组的下标记录这类,head的数值表示最后一类的读入位置。和最短路里链式前向星的查找类似。

#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>#include <map>using namespace std;const int maxn=10010;int pre[maxn],val[maxn],n,m,l,r,w;char s[10];int find(int x){    if(pre[x]==x) return x;    int tmp=find(pre[x]);    val[x]=(val[x]+val[pre[x]])%2;    return pre[x]=tmp;}int mix(int x,int y,int z)//语句正确,mix返回1,否则返回0。{    int fx=find(x);    int fy=find(y);    if(fx!=fy)    {        pre[fx]=fy;        val[fx]=(val[y]-val[x]+z)%2;        return 1;    }    else    {        if(abs(val[x]-val[y])%2==z) return 1;        return 0;    }}int main(){#ifdef LOCAL    freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);#endif    while(~scanf("%d",&n)&&n)    {        for(int i=0;i<maxn;i++)        {            pre[i]=i;            val[i]=0;        }        scanf("%d",&m);        int ok=0;        int ans=0;        int index=0;        map<int,int> mp;        for(int i=1;i<=m;i++)        {            scanf("%d%d%s",&l,&r,s);            if(s[0]=='e') w=0;            else w=1;            l--;//这样做就可以合并相邻的区间,例如:读入l=1,r=2和l=3,r=4            if(mp.find(l)==mp.end()) mp[l]=index++;            //find()函数返回一个迭代器指向键值为key的元素,如果没找到就返回指向map尾部的迭代器            if(mp.find(r)==mp.end()) mp[r]=index++;            //假设前x条语句是正确的,第x+1条是错的。那么前x次读入ok都为0,第x+1次读入由于ok=0,mix()返回0            //所以执行else语句,ok变为1,ans=i-1=(x+1)-1=x.从x+2开始由于ok=1,不会执行||后面的判断,恒continue.            if(ok||mix(mp[l],mp[r],w)) continue;            else ok=1;            if(ok) ans=i-1;        }        if(ok==0) ans=m;//所有的语句都是正确的        printf("%d\n",ans);    }    return 0;}
#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <cstring>#include <map>using namespace std;const int maxn=5050;int n,m,l,r,w,tot;int head[maxn],val[maxn],pre[maxn];char s[10];struct Point{    int value,next;}point[maxn];int hash(int n){    int m=n%maxn;    for(int i=head[m];i!=-1;i=point[i].next)        if(point[i].value==n) return i;    point[tot].value=n;    point[tot].next=head[m];    head[m]=tot++;    return (tot-1);}int find(int x){    if(pre[x]==x) return x;    int tmp=find(pre[x]);    val[x]=(val[x]+val[pre[x]])%2;    return pre[x]=tmp;}int mix(int x,int y,int z){    int fx=find(x);    int fy=find(y);    if(fx!=fy)    {        pre[fx]=fy;        val[fx]=(val[y]-val[x]+z)%2;        return 1;    }    else    {        if(abs(val[x]-val[y])%2==z) return 1;        return 0;    }}int main(){#ifdef LOCAL    freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);#endif    while(~scanf("%d",&n)&&n)    {        memset(head,-1,sizeof(head));        memset(val,0,sizeof(val));        for(int i=0;i<maxn;i++)            pre[i]=i;        tot=0;        scanf("%d",&m);        int ans=m;        int ok=0;        for(int i=1;i<=m;i++)        {            scanf("%d%d%s",&l,&r,s);            l=hash(l-1);            r=hash(r);            if(s[0]=='e') w=0;            else w=1;            if(ok||mix(l,r,w)) continue;            else ok=1;            if(ok) ans=i-1;        }        printf("%d\n",ans);    }    return 0;}
0 0