使用并查集来维护不同的类关系

我们理解并查集这个数据结构的时候不要过于死板,我们要知道

并查集是用来维护关系的,而不是单纯一味去归并,归并,归并

下面给出一个问题尝试用并查集来解决:一共有两个类,然后告诉你若干组数据,每一组数据的两个元素不是一类的,然后在线判断两个元素是否是同一类

这个时候如果你只会归并就行不通的,还需要一些特殊的处理

我们需要在并查集的那个数组的基础之上,需要另一个数组来记录这种特殊的现象

int set[maxn],a[maxn];
//a表示这个节点和父节点的关系,0表示相同1表示不同 

接下来我们的路径压缩加找祖宗函数也需要相应的调整,要不断更新a的值才行

int find(int x)
{
    if (x==set[x]) return x;
    //x的父节点是祖先节点的情况,不需要改变a的值
    int t=find(set[x]);
    a[x]=(a[set[x]]+a[x])%2;
    //判断归并之后x和祖先的团伙关系
    return set[x]=t;
}

归并的时候还是很简单的,但是也要同时去更新a的值

void Union(int x, int y)
{
    int fx=find(x);
    int fy=find(y);
    set[fx]=fy;
    //根据x和y不同确定x和x的祖先节点的同伙关系
    if (a[y]==0)
        a[fx]=1-a[x];
    else
        a[fx]=a[x];
}

我们在判断的时候,已知的情况都已经归并到一棵树里面,并且有a数组记录已知情况下所有元素的关系,直接判断即可

fx=find(x);
                fy=find(y);
                if (fx!=fy)
                    printf("Not sure yet.\n");
                else if(a[x]==a[y])
                    printf("In the same gang.\n");
                else
                    printf("In different gangs.\n");

接下来我们给出完整的实现,这道题的大意是这样的,有两个犯罪团伙,然后告诉你若干个关系,关系是两个犯人不是一个团伙的,然后在线判断给定的两个犯人之间的关系

 1 //一共有两类,给定某两个元素之间的不同类关系
 2 //判断当前给定情况下某两个元素是否同类
 3 #include<iostream>
 4 #include <cstdio>
 5 #include <cstring>
 6 using namespace std;
 7 const int maxn=100005;
 8 int t,n,m;
 9 int fx,fy,x,y;
10 char c;
11 int set[maxn],a[maxn];
12 //a表示这个节点和父节点的关系,0表示相同1表示不同
13 int find(int x)
14 {
15     if (x==set[x]) return x;
16     //x的父节点是祖先节点的情况,不需要改变a的值
17     int t=find(set[x]);
18     a[x]=(a[set[x]]+a[x])%2;
19     //判断归并之后x和祖先的团伙关系
20     return set[x]=t;
21 }
22 void Union(int x, int y)
23 {
24     int fx=find(x);
25     int fy=find(y);
26     set[fx]=fy;
27     //根据x和y不同确定x和x的祖先节点的同伙关系
28     if (a[y]==0)
29         a[fx]=1-a[x];
30     else
31         a[fx]=a[x];
32 }
33 int main()
34 {
35
36     cin>>t;
37     while (t--)
38     {
39         cin>>n>>m;
40         for (int i=1; i<=n; i++)
41         {
42             set[i] = i;
43             a[i] = 0;
44         }
45         while(m--)
46         {
47             cin>>c>>x>>y;
48             if (c==‘A‘)
49             {
50                 fx=find(x);
51                 fy=find(y);
52                 if (fx!=fy)
53                     printf("Not sure yet.\n");
54                 else if(a[x]==a[y])
55                     printf("In the same gang.\n");
56                 else
57                     printf("In different gangs.\n");
58             }
59             else
60                 Union(x, y);
61         }
62     }
63     return 0;
64 }

原文地址:https://www.cnblogs.com/aininot260/p/9304501.html

时间: 2024-08-06 19:09:39

使用并查集来维护不同的类关系的相关文章

51nod 1515 明辨是非 并查集+set维护相等与不等关系

考试时先拿vector瞎搞不等信息,又没离散化,结果好像MLE:后来想起课上讲过用set维护,就开始瞎搞迭代器...QWQ我太菜了.. 用并查集维护相等信息,用set记录不相等的信息: 如果要求变量不等,若不和并查集矛盾,就拿set互相记录一下,YES:矛盾就NO 如果要求变量相等, 1.x记录的不等的变量中有y,说明矛盾,NO 2.若祖先不等,那就合并两个变量所在的并查集(合并两个并查集的祖先),size大的并到小的上,set暴力转移集合不相等的信息,YES 否则YES #include<cs

逆向思维 + 用并查集动态维护连通块的个数——Luogu P1197题解

题目大意: 给你一个 $ n $ 个点的图与 $ m $ 条边,接下来给出一个长度为 $ k $ 个整数,按照给出整数的顺序依次删掉对应编号的点,求出一开始的连通块的个数与接下来每次删除一个点后的连通块的个数.(连通块就是一个点集,这个集合里面的任意两个点都可以互相到达) 思路: 大体思路: 这个题目如果正向考虑会很难做,因为我们要每次维护一个不断删点的图的连通块个数是很难弄的.所以我们要倒着考虑.假如我们把删点的过程倒着考虑,就变成了从最后一个点往前添加进这个图里面的过程.所以这样问题就变成了

poj1182 并查集

题目连接:http://poj.org/problem?id=1182 基础并查集,需要维护与根节点关系,解析见代码: /* poj 1182 并查集 思路分析:让你分析这些话里面多少假的 只需要用一个并查集将已经给出的这些元素存起来 同时记录每个元素与他们根节点关系,如果根结点相同 但是关系不符合就是出现了矛盾. 关系有三种:同类 记为0 吃根节点 1 被根节点吃 2 这样也是为了与他给出的d关系一致 d-1就与我们规定的关系一致了 并查集的关键是路径压缩,在压缩路径的同时我们要更新与根节点关

poj 1456 Supermarket(并查集维护区间)

 题意:有一些货物,每个货物有价值和卖出的截至日期,每天可以卖一个货物,问能卖出的最大价值是多少. 思路:算法不难想到,按价值降序排列,对于每一件货物,从deadline那天开始考虑,如果哪天空闲那么将货物在该天卖出. 如果直接暴力来做,复杂度为o(n*n),显然不行.可以用并查集来维护当前ddl之前空闲的最近的一天,如果父节点为0说明deadline之前没有空闲的时间,那么该货物就无法卖出. #include<cstdio> #include<cstring> #includ

YYHS-猜数字(并查集/线段树维护)

题目描述 LYK在玩猜数字游戏. 总共有n个互不相同的正整数,LYK每次猜一段区间的最小值.形如[li,ri]这段区间的数字的最小值一定等于xi. 我们总能构造出一种方案使得LYK满意.直到-- LYK自己猜的就是矛盾的! 例如LYK猜[1,3]的最小值是2,[1,4]的最小值是3,这显然就是矛盾的. 你需要告诉LYK,它第几次猜数字开始就已经矛盾了. 输入 第一行两个数n和T,表示有n个数字,LYK猜了T次.    接下来T行,每行三个数分别表示li,ri和xi. 输出 输出一个数表示第几次开

【数轴染色+并查集路径压缩+加速】

http://codevs.cn/problem/1191/ [思路] 每次我们染了一个区间,下一次如果还要染这个区间或者它的子区间的话,我们就不用处理了.这样我们可以把每一个区间抽象成一个点,用并查集来维护.合并时将[L,R]区间全部合并,[L,R]区间的每个点的父节点都通过路径合并变成L-1,然后n–.这样每个点只会被合并一次,复杂度O(nα(n)) ,跑得很快. 如 3 3 fa[3]=2,操作一次 5 7, fa[7]=fa[6]=fa[5]=4,操作三次 2 8: fa[8]=fa[7

POJ1182 食物链---(经典种类并查集)

题目链接:http://poj.org/problem?id=1182 食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 69207   Accepted: 20462 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食

1163 最高的奖励 贪心 + 并查集

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1163 首先如果时间大于n,也就是相当于不限时了,因为完成前n - 1项任务需要时间n - 1,不影响我的第n项. 首先按价值排序,然后这个价值安排在它准备过期的那一天,如果被占据了,就找下一天,就能优先吃到了最大值.而且你吃其他也是耗费一个空间,所以吃个更大的是最优的. 然后可以用并查集来维护,记录topre[i]表示第i个位置的上一个空位是谁. 就能加速找到了. 不然

FZU 2112 并查集、欧拉通路

原题:http://acm.fzu.edu.cn/problem.php?pid=2112 首先是,票上没有提到的点是不需要去的. 然后我们先考虑这个图有几个联通分量,我们可以用一个并查集来维护,假设有n个联通分量,我们就需要n-1条边把他们连起来. 最后对于每个联通分量来说,我们要使它能一次走完,就是要求他是否满足欧拉通路,也就是这个联通分量中至多有2个度为奇数的点,每多出2个度为奇数的点,就多需要一条边(因为单个连通分量的所有点的度数之和为偶数,所以不可能存在奇数个奇数度数的点). 1 #i