2019 UESTC ACM Training for Data Structures[C](区间合并+并查集)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/getsum/article/details/91042200

问题描述:依次给出n个闭区间(端点都是整数),两个闭区间如果有重合就会合并成一个(端点重合也算)。求新给出一组闭区间时,当前的区间个数。

区间合并问题。考虑每次枚举,那么至少得枚举到每一个联通块的边界,联通块在最坏情况下达到n,因此为O(n^2)算法。
考虑借助并查集合并区间的“集合”。将区间内的所有点连向左边界。然后更新最小的不属于该集合的元素。
在我们对每一次的集合个数进行回答的时候,我们就可以用类似于链表的方式查找不同集合的个数。这样就避免了O(n)枚举每个元素的集合。
注意到区间端点较大,但是输入数据量相对较小,因此记得对输入数据离散化。

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<cmath>
#include<map>
#define LL long long
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e6+5;
map<int,int>tosm;
int n,s[maxn],tot,num,fa[maxn],Last[maxn],ans,a[maxn];
bool vis[maxn];
int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		s[2*i-1]=a[2*i-1]=x,s[2*i]=a[2*i]=y;
	}
	sort(s+1,s+1+2*n);
	for(int i=1;i<=2*n;i++)
		if(!tosm[s[i]])tosm[s[i]]=++num;
    //对输入数据离散化
	for(int i=1;i<=num;i++)fa[i]=i,Last[i]=i+1;
    //初始化数组
	for(int i=1;i<=n;i++){
		int l=tosm[a[2*i-1]],r=tosm[a[2*i]];
		int rt=getfa(l);
		int Next;
		for(int j=l;j<=r;j=Next){
			Next=Last[j];
			vis[j]=1;
			fa[getfa(j)]=rt;
			Last[j]=Last[r];
		}
		ans=0;
		for(int j=1;j<=num;j=Last[j])
			if(vis[j]&&getfa(j)!=getfa(j-1))ans++;
		printf("%d ",ans);
	}
}

猜你喜欢

转载自blog.csdn.net/getsum/article/details/91042200