Codeforces 556 C Restructuring Company 并查集

https://cn.vjudge.net/contest/240521#problem/C

题意:三种操作:

  1. 将a和b放入一个并查集。
  2. 将区间[a,b]内的所有元素放入一个并查集。
  3. 询问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;
}

猜你喜欢

转载自blog.csdn.net/nwpu2017300135/article/details/81175026
今日推荐