Poj(1703),种类并查集

题目链接:http://poj.org/problem?id=1703

已经不是第一次接触种类并查集了,直到今天才搞懂。

感谢红黑联盟,感谢杰哥!!!

每个节点只要关系确定,不管是不是同一个集合里面,都把他们放到一个集合里面,用一个rank[]数组记录他们与根节点的关系,比较神奇的地方有两处:

1、find函数里面,因为find是递归写的,不断往上找,不断更新rank[x](与根节点的关系),这个%k,也是很牛逼的,2种类型,标号只有01;

2、Union函数里面,更新rank[fy],rank[y]这里是(rank[x] - rank[y] +1)%2,这里特值法证明一下吧,我智商已经不够用了,比如说,新的节点0,合并后,就往上找,比如说找到了110,这个点肯定不是跟根同一个集合,0-A,0-B,然后(0-0+1)%2==1;

啊哈,特例搞一下吧,脑容量不够了。

#include<cstdio>

const int N = 100005;
int n, m, f[N], rank[N];

void init()
{
    for(int i=1; i<=n; ++i)
        f[i]=i,rank[i]=0;
}

int find(int x)
{
    if(x==f[x])
        return f[x];
    int fa=f[x];
    f[x] = find(f[x]);
    rank[x] = (rank[x]+rank[fa])%2;
    return f[x];
}

bool Union(int x,int y)
{
    int fx=find(x), fy=find(y);
    if(fx==fy) return false;
    f[fy] = fx;
    rank[fy] = (rank[x]-rank[y]+1)%2;
}

int main()
{
    int T,a,b,fa,fb;
    char ch;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%*c",&n,&m);
        init();
        for(int i=0; i<m; ++i)
        {
            scanf("%c%d%d%*c",&ch,&a,&b);
            if(ch==‘D‘)
            {
                Union(a,b);
            }
            else
            {
                fa = find(a), fb=find(b);
                if(fa==fb)
                {
                    if(rank[a]==rank[b]) puts("In the same gang.");
                    else puts("In different gangs.");
                }
                else
                    puts("Not sure yet.");
            }
        }
    }
    return 0;
}
时间: 2024-08-03 09:22:22

Poj(1703),种类并查集的相关文章

Poj(1182),种类并查集

题目链接:http://poj.org/problem?id=1182 再次熟练种类并查集,又积累点经验,和技巧,rank 0 2 1 先计算father[x] ,再更新rank[x]; #include <stdio.h> int father[50010]; int rank[50010]; int Find_Set (int x) { int tmp; if(x!=father[x]) { tmp = father[x]; father[x] = Find_Set(father[x]);

种类并查集,Poj(1703)

题目链接:http://poj.org/problem?id=1703 第一次做种类并查集,有的地方还不是很清楚,想了一上午,有点明白了,这里记录一下. 这里我参考的红黑联盟的题解. 关键:种类并查集与带权并查集实质上的差别并不大, 关键的区别就是种类并查集只是带权并查集再弄个%取余操作而已,然后余数就表示他属于哪个种类. rank数组表示节点和父节点的关系(也可以理解为他的种类). find中,找到x的父节点后,那么更新他与父节点的关系,rank[x] = (rank[x]+rank[fa])

poj 2492 a bug&#39;s life 简单种类并查集

题意大致为找同性恋的虫子.... 这个比食物链要简单些.思路完全一致,利用取余操作实现关系之间的递推. 个人感觉利用向量,模和投影可能可以实现具有更加复杂关系的并查集. 1 #include<cstdio> 2 using namespace std; 3 const int MAXN=50010; 4 int fa[MAXN]; 5 int rel[MAXN]; // 0代表同类,1代表吃fa[i],2代表被吃 6 void _set(int n) 7 { 8 for(int i=1;i&l

poj 1182 食物链(种类并查集 ‘初心者’)

题目链接:http://poj.org/problem?id=1182 借着这题可以好好理解一下种类并查集,这题比较简单但挺经典的. 题意就不解释了,中问题. 关于种类并查集结局方法也是挺多的 1扩增倍数. 就是有几种关系就建立几倍数组,具体方法在这里不详细说了,这种方法有弊端 比较复杂而且内存消耗比较大如果关系比较多就容易爆掉. 2向量的方法. 这种方法要详细解说一下.这个方法好处都有啥.......(自行脑补后面的话) 这个方法的优点占用内存比较小而且比较简洁.只要找到关系就行. 下面就用方

HDU 1829 &amp;&amp; POJ 2492 A Bug&#39;s Life(种类并查集)

题目地址:HDU 1829     POJ 2492 这个题可以用两种方法做,第一眼看完题是觉得用dfs染色判断二分图.然后又写的刚学的种类并查集.原来并查集可以这样用,真是神奇.. dfs染色代码: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #incl

【POJ】2492 A bug&#39;s life ——种类并查集

A Bug's Life Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 28211   Accepted: 9177 Description Background Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they feature two different genders

带权并查集(含种类并查集)【经典模板】 例题:①POJ 1182 食物链(经典)②HDU - 1829 A bug&#39;s life(简单) ③hihoCoder 1515 : 分数调查

带权并查集: 增加一个 value 值,并且每次合并和查找的时候需要去维护这个 value 例题一 :POJ 1182 食物链(经典) 题目链接:https://vjudge.net/contest/339425#problem/E 带权并查集的解法 定义两个数组fa[ ]和rela[ ],fa用来判断集合关系,rela用来描述其与根节点的关系.因为关系满足传递性,所以可以推导出给出条件下的当前关系,在判断与之前已有关系是否矛盾. 本题的解法巧妙地利用了模运算,rela数组用0表示同类,1表示当

poj 1182食物链【种类并查集】

食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 49310   Accepted: 14382 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是"1 X Y",表示X和Y是同

POJ 1182食物链 种类并查集的经典

题目链接:http://icpc.njust.edu.cn/Problem/Pku/1182/ 题意:给出动物之间的关系,有几种询问方式,问是真话还是假话. 定义三种偏移关系: x->y 偏移量0时 x和y同类 x->y 偏移量1时 x被y吃 x->y 偏移量2时 x吃y 定义 rela[x]=rx->x; 如x,y不在同一个集合中, 由rx->ry=rx->x + x->y + y->ry=(rx->x)+(x->y)-(ry->y)可得