https://cn.vjudge.net/contest/240521#problem/C
题意:三种操作:
- 将a和b放入一个并查集。
- 将区间内的所有元素放入一个并查集。
- 询问a和b是不是在一个并查集内
题解:1,3很简单,难点在于2;
一个一个合并肯定是超时。所以要想办法优化。n个元素,如果一个区间一个区间得合并,肯定很快就大部分就在一个区间里了。
所以用数组nex[i]表示i元素下个区间得开头。
#include <iostream>
#include <cstdio>
using namespace std;
int p[2000005],nex[2000005];
int finde(int x){
if(x==p[x])return x;
return p[x]=finde(p[x]);
}
void join(int x,int y){
x=finde(x);
y=finde(y);
p[x]=y;
}
int n,q;
void in_it(){
int i;
for(i=1;i<=n;i++){
p[i]=i;
nex[i]=i+1;//一开始没有区间合并,所以指向下一个
}
}
int main()
{
int a,b,c;
int i,tar;
scanf("%d%d",&n,&q);
in_it();
while(q--){
scanf("%d%d%d",&c,&a,&b);
if(c==1){
join(a,b);
}
else if(c==3){
a=finde(a);
b=finde(b);
if(a==b)printf("YES\n");
else printf("NO\n");
}
else {
for(i=a+1;i<=b;i=tar){//tar指向下一个可能需要合并得元素,tar之前得元素在之前区间合并操作里已经被合并了
join(i,i-1);
tar=nex[i];
nex[i]=nex[b];//区间[a.b]内的在这个for之后都会变成一个并查集内,所以下次进行区间合并,保证直接跳到b。
}
}
}
// cout << "Hello world!" << endl;
return 0;
}