poj 1733 并查集(奇偶校验,判断第一个矛盾)

题意:一个由0,1组成的数字串,现在你问一个人,第i位到第j位的1的个数为奇数还是偶数。一共会告诉你n组这样的数。要你判断前k组这个人回答的都是正确的,到第k+1组,这个人说的是错的,要你输出这个k,要是这个人回答的都是正确的,则输出组数。

思路:并查集。注意输入的区间非常大,所以要离散化一下。离散化的时候还要注意,如果两个数字相邻但是其差不为1,那么中间必须再加上另一个数。比如将出现的数字排序后连续的两个数字是3和8,那么中间必须加上一个数字(4~7都行)。这是为了防止这样的情况:3~3和8~8都是奇数,3~8也是奇数。如果中间不加数,离散化之后就会判断为错,实际上这是可能的。

接着就是并查集的过程,与找同性恋虫子那题类似。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define clr(s,t) memset(s,t,sizeof(s))
#define N 15005
struct node{
    int x,y,flag;
}p[N];
int s[N<<1],t[N<<1],f[N],parity[N];
int T,n;
int find(int x){
    int tmp = f[x];
    if(f[x] == x)
        return x;
    f[x] = find(f[x]);
    parity[x] = (parity[tmp]+parity[x])&1;
    return f[x];
}
int main(){
    int i,j,a,b,xx,yy,len,top;
    char str[10];
    clr(parity, 0);
    scanf("%d",&T);
    scanf("%d",&n);
    if(!n){
        printf("0\n");
        return 0;
    }
    len = 0;
    for(i = 1;i<=n;i++){
        scanf("%d %d %s",&p[i].x,&p[i].y,str);
        s[len++] = p[i].x;
        s[len++] = p[i].y;
        p[i].flag = (str[0]=='o');
    }
    sort(s,s+len);
    top = 0;
    t[top++] = s[0];
    for(i = 1;i<len;i++){
        if(s[i] - s[i-1] > 1)//中间差一个数至关重要
            t[top++] = s[i-1]+1;
        t[top++] = s[i];
    }
    memcpy(s, t, sizeof(s));
    len = top;
    len = (int)(unique(s, s+len) - s);
    
    for(i = 0;i<=len;i++)
        f[i] = i;
    for(i = 1;i<=n;i++){
        a = (int)(lower_bound(s, s+len, p[i].x)-s);
        b = (int)(lower_bound(s, s+len, p[i].y)-s+1);
        xx = find(a);
        yy = find(b);
        if(xx == yy){
            if((parity[a]^parity[b]) != p[i].flag)
                break;
        }else if(xx < yy){
            f[yy] = xx;
            parity[yy] = (parity[a] +parity[b] + p[i].flag) & 1;
        }else{
            f[xx] = yy;
            parity[xx] = (parity[b] +parity[a] + p[i].flag) & 1;
        }
    }
    printf("%d\n",i-1);
    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值