51nod 1515 明辨是非

题目描述:

给$n$组操作,每组操作形式为 x y p。
当$p$为 1 时,如果第$x$变量和第$y$个变量可以相等,则输出YES,并限制他们
相等;否则输出 NO,并忽略此次操作。
当$p$为 0 时,如果第$x$变量和第$y$个变量可以相等,则输出 YES,并限制他
们相等;否则输出 NO,并忽略此次操作。

思路:

看到维护相等关系,自然的想到并查集。

但是本题要维护相等和不等关系,普通的并查集无法满足。

之后怎么办呢?在考场的我就懵逼了。后来发现用set暴力维护每个并查集内不能和谁相等就完了。好弱智啊!我果然还是太菜了。

在合并相等关系时可以找到元素个数较少的一个set,将他直接插进另一个set里。这种暴力被称为启发式合并。奇技淫巧

合并不等关系时直接加入set里就好了。

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<set>
#include<map>
using namespace std;
set<int>s[2000005];
set<int>::iterator it;
map<int,int>a;
int f[2000005];
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
int main()
{
//    freopen("TrueFalse.in","r",stdin);
//    freopen("TrueFalse.out","w",stdout);
    int n;
    scanf("%d",&n);
    int i,cnt=0;
    for(i=1;i<=n*2;i++)
        f[i]=i;
    for(i=1;i<=n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        a[x]?(x=a[x]):(x=a[x]=++cnt);
        a[y]?(y=a[y]):(y=a[y]=++cnt);
        int opt;
        scanf("%d",&opt);
        int u=find(x);
        int v=find(y);
        if(opt==1)
        {
            if(s[u].count(v))
                puts("NO");
            else if(u!=v)
            {
                if(s[u].size()>s[v].size())
                    swap(u,v);
                f[u]=v;
                for(it=s[u].begin();it!=s[u].end();it++)
                {
                    s[*it].erase(u);
                    s[*it].insert(v);
                    s[v].insert(*it);
                }
                puts("YES");
            }
            else
                puts("YES");
        }
        else
        {
            if(u==v)
                puts("NO");
            else
            {
                s[u].insert(v);
                s[v].insert(u);
                puts("YES");
            }
        }
    }
}

 

posted @ 2019-08-02 21:11  星辰节度使  阅读(182)  评论(0)    收藏  举报