前言
很直白的板子题,虽然没想到并查集只是个普及水平的东西(虽然的确挺简单的),还是在前年第一次在省赛里边听学姐提到了这个,现在终于真正会了(真的会了?)。
题目
原题链接: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());
}
}