【题解】洛谷P3367 并查集

前言

很直白的板子题,虽然没想到并查集只是个普及水平的东西(虽然的确挺简单的),还是在前年第一次在省赛里边听学姐提到了这个,现在终于真正会了(真的会了?)。


题目

原题链接:https://www.luogu.org/problemnew/show/P3367

P3367 并查集 时空限制

题目描述
如题,现在有一个并查集,你需要完成合并和查询操作。

输入格式
第一行包含两个整数N、M,表示共有N个元素和M个操作。

接下来M行,每行包含三个整数Zi、Xi、Yi

当Zi=1时,将Xi与Yi所在的集合合并

当Zi=2时,输出Xi与Yi是否在同一集合内,是的话输出Y;否则话输出N

输出格式
如上,对于每一个Zi=2的操作,都有一行输出,每行包含一个大写字母,为Y或者N

样例
输入样例#1:

4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4

输出样例#1:
N
Y
N
Y

说明
时空限制:1000ms,128M

数据规模:

对于30%的数据,N<=10,M<=20;

对于70%的数据,N<=100,M<=1000;

对于100%的数据,N<=10000,M<=200000。


解题思路

并查集就是指具有一定关系的对象的集合,可以通过它快速的查找到哪个元素位与哪个集合,以及某些元素是否包含于同一集合中

那么,接下来说说它的实现思路,如:
a与b约定决斗,输家成为赢家的小弟,假设b败给了a,于是b将会成为a的小弟,那么我们可以得到:

t[b] = a

这里就实现了第一步,让两个元素之间建立起关系。
那么之后又出现了第三者呢?
比如,c也和b决斗然后c败给了b,所以c将会成为b的小弟,有:

t[c] = b

这样就引出了一个新的问题——“我小弟的小弟不是我的小弟”,所以为了解决这个矛盾我们应该让a成为c的最终老大,也就是:

t[c] = t[b]

这是三个人的情况,那么要是人更多呢,又会出现同样的问题了,显然上面的处理虽然注意到了问题却没有完全解决问题,所以正确的处理应当是——让b的最终老大成为c的最终老大(因为c可能已经有了一个老大):

static int up(int n){
		if(t[n] == n)return n;//如果最终老大是自己则说明已经是最大的老大,返还自己
		return t[n] = up(t[n]);//在寻找最终老大的过程中顺带消除和最终老大的中间人
	}

t[up(a)] = up(b)


解题代码

完整代码如下:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.StringTokenizer;

public class Main {
 
	static int t[] = new int [10050];
	
	static int up(int n){
		if(t[n] == n)return n;
		return t[n] = up(t[n]);
	}
	
    public static void main(String[] args) {
        Inputreader sc = new Inputreader();
        while(sc.hasNext()){
        	int n = sc.nextInt();
        	int m = sc.nextInt();
        	for(int i = 1;i <= n;i++)
        		t[i] = i;
        	for(int j = 1;j <= m;j++){
        		int k = sc.nextInt();
        		int a = sc.nextInt();
        		int b = sc.nextInt();
        		if(k == 1)
        			t[up(a)] = up(b);
        		else
        			if(up(a) == up(b))
        				System.out.println("Y");
        			else 
        				System.out.println("N");
        	}
        	}
        }
    }

  
class Inputreader
{
    BufferedReader buf;
    StringTokenizer tok;
    Inputreader()
    {
        buf = new BufferedReader(new InputStreamReader(System.in));
    }
    boolean hasNext()
    {
        while(tok == null || !tok.hasMoreElements()) 
        {
            try
            {
                tok = new StringTokenizer(buf.readLine());
            } 
            catch(Exception e) 
            {
                return false;
            }
        }
        return true;
    }
    String next()
    {
        if(hasNext()) return tok.nextToken();
        return null;
    }
    int nextInt()
    {
        return Integer.parseInt(next());
    }
    long nextLong()
    {
        return Long.parseLong(next());
    }
    double nextDouble()
    {
        return Double.parseDouble(next());
    }
    BigInteger nextBigInteger()
    {
        return new BigInteger(next());
    }
    BigDecimal nextBigDecimal()
    {
        return new BigDecimal(next());
    }
}

猜你喜欢

转载自blog.csdn.net/Jourofant/article/details/107496900