HDU 3234 Exclusive-OR Regional的题就是硬啊卧槽

带权并查集,思路很清晰,代码很难看。

对于 I u v ,分以下几种情况不合法。

1.num[u] 已确定 && num[u]  != v 。

2.num[u] 的根已确定,若num[u] == v与根节点有冲突。

若合法,则修改num[u] 且 修改num[u]的根节点的信息。


对于 I u v w   ,分以下几种情况不合法。

1.num[u] ,num[v] 均已确定或均可通过根节点确定 且 num[u]^num[v] != w;

2.若u,v在一个集合内,且num[u] ^ num[root]  ^ num[v] ^num[root] = num[u]^num[v] != w;

若合法,且u,v不在一个集合内,合并u,v所在的集合,若num[root_u]已知,num[root_v]未知(设root_v合并后新集合的根),则更新num[root_v]

对于询问:

首先将确定的数的抑或结果计算出来,然后对于剩下的必须符合可以分成X份,每份中必须有偶数个元素。

因为任意两个同根的元素可以由num[u] ^ num[root]  ^ num[v] ^num[root] = num[u]^num[v] 得出。

否则输出I don't know.


有些题解的解法简直炫酷到没朋友,通过虚拟出一个值为零的节点节省了很多代码,可见预先设计出好的思路是有多重要。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <string>
#include <map>

#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-8)
#define LL long long
#define ULL unsigned long long
#define _LL __int64
#define INF 0x3f3f3f3f
#define Mod 300

using namespace std;

struct N
{
    int fa,re;
}st[20010];

int num[20010];

int Find(int x,int &R)
{
    int f = x,re = 0,tre = 0,temp,tf;

    while(f != st[f].fa)
    {
        re ^= st[f].re;
        f = st[f].fa;
    }

    R = re;

    while(x != st[x].fa)
    {
        temp = st[x].re;
        tf = st[x].fa;

        st[x].re = re^tre;
        st[x].fa = f;

        tre ^= temp;
        x = tf;
    }

    return x;
}

bool Merge(int u,int v,int w)
{
    int fu,fv,ru,rv;

    fu = Find(u,ru);
    fv = Find(v,rv);

    if(num[fu] != -1)
        num[u] = num[fu]^ru;

    if(num[fv] != -1)
        num[v] = num[fv]^rv;

    if(num[u] != -1 && num[v] != -1)
        return (num[u]^num[v]) == w;

    if(fu == fv)
    {
        return (w^ru) == rv;
    }
    else
    {
        st[fu].fa = fv;
        st[fu].re = w^rv^ru;

        if(num[fv] == -1 && num[fu] != -1)
        {
            num[fv] =  num[fu]^st[fu].re;
        }

    }
    return true;
}

bool mark[20];
int  qu[20];

void JudgeQ(char *s)
{
    int i,j,k = 0;

    for(i = 0;s[i]  < '0' || s[i] > '9'; ++i)
        ;

    for(;!(s[i]  < '0' || s[i] > '9'); ++i)
        ;

    for(;s[i] == ' '; ++i)
        ;

    int anw = 0,temp,x;

    while(s[i] != '\0')
    {
        temp = 0;

        for(;!(s[i]  < '0' || s[i] > '9'); ++i)
        {
            temp += (s[i]-'0');
            temp *= 10;
        }

        temp = temp/10 + 1;

        for(;s[i] == ' '; ++i)
            ;
        qu[k++] = temp;
    }

    for(i = 0;i < k; ++i)
    {
        if(num[qu[i]] != -1)
        {
            anw ^= num[qu[i]];
            continue;
        }
        if(num[Find(qu[i],x)] != -1)
        {
            num[qu[i]] = num[Find(qu[i],x)]^x;
            anw ^= num[qu[i]];
        }
    }

    memset(mark,false,sizeof(mark));

    int ru,rv;

    for(i = 0;i < k; ++i)
    {
        if(mark[i] == false && num[qu[i]] == -1)
        {
            for(j = i+1;j < k; ++j)
            {
                if(mark[j] == false && num[qu[i]] == -1 && Find(qu[i],ru) == Find(qu[j],rv))
                {
                    mark[i] = true,mark[j] = true,anw ^= (ru^rv);
                    break;
                }
            }

            if(mark[i] == false)
            {
                printf("I don't know.\n");
                return;
            }
        }
    }

    printf("%d\n",anw);
}

int Judge(char *s)
{
    int i;

    for(i = 0;s[i]  < '0' || s[i] > '9'; ++i)
        ;

    for(;s[i] == ' '; ++i)
        ;

    int ans = 0;

    while(s[i] != '\0')
    {
        ans++;
        for(;!(s[i]  < '0' || s[i] > '9'); ++i)
            ;
        for(;s[i] == ' '; ++i)
            ;
    }
    return ans;
}

int main()
{
    int i,n,m,icase = 1;

    char s[100],ord[100];

    int u,v,w;

    int ans;
    bool wrong,first;

    while(scanf("%d %d%*c",&n,&m) && (n||m))
    {
        for(i = 1;i <= n; ++i)
            st[i].fa = i,st[i].re = 0,num[i] = -1;

        wrong = false,first = true;
        ans = 0;

        printf("Case %d:\n",icase++);

        while(m--)
        {
            gets(s);
            if(first == false)
                continue;
            if(s[0] == 'I')
            {
                ans++;
                if(Judge(s) == 3)
                {
                    sscanf(s,"%s %d %d %d",ord,&u,&v,&w);

                    u++,v++;

                    if(Merge(u,v,w) == false)
                        wrong = true;
                }
                else
                {
                    sscanf(s,"%s %d %d",ord,&u,&w);

                    u++;

                    if(num[u] == -1 && num[Find(u,v)] == -1)
                    {
                        num[u] = w;
                        num[Find(u,v)] = w^st[u].re;
                    }
                    else if(num[u] == -1)
                    {
                        if((num[Find(u,v)]^st[u].re) != w)
                            wrong = true;
                        else
                            num[u] = w;
                    }
                    else if(num[u] != w)
                        wrong = true;
                }

                if(wrong && first)
                {
                    printf("The first %d facts are conflicting.\n",ans);
                    first = false;
                }
            }
            else
            {
                JudgeQ(s);
            }
        }
        printf("\n");
    }

    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值