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

本文解析了POJ1733 Party Game问题,通过使用并查集和哈希表来解决大规模数据集的问题。文章详细介绍了如何处理非零即一的数字序列,并针对给定的条件判断哪些陈述是正确的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值