其他分享
首页 > 其他分享> > acw4412. 构造数组-区间合并or并查集

acw4412. 构造数组-区间合并or并查集

作者:互联网

4412. 构造数组-区间合并or并查集

题目大意:

有两个数列,给数列a和b,a已知,b未知。若ai==aj则表示在b数列中[i,j]区间所有数相等。现在b[0]=0,问b数组有多少种可能。

思路和代码:

比较好想,只要看a有几个区间,答案就是2^(x-1)。

这题给出两种做法,区间合并并查集

//区间合并做法
/*
先对所有区间按照左端点排序,再去合并
合并时有三种情况:
now: s----------e
1===>    l---r
2===>   l-------------r
3===>                   l-----r
其中情况1和情况2只要更新e值,情况3要更新整个区间。
*/
void merge(vct<pll> &seg){
	vct<pll> res ;
	sort(seg.begin() , seg.end()) ;
	ll st = -2e9 , ed = -2e9 ;
	
	for(auto s : seg){
		if(ed < s.fi){
			res.pb({st , ed}) ;
			st = s.fi ;
			ed = s.se ;
		}else ed = max(ed , s.se) ;
	}
	seg = res ;
}

void solve3(){
	ll n ;
	cin >> n ;
	
	map<ll , ll> st , ed ;
	vct<ll> num ;
	
	rep(i , 1 , n){
		ll tmp ; cin >> tmp ;
		if(!st[tmp]){
			num.pb(tmp) ;
			st[tmp] = i ;
			ed[tmp] = i ;
		}else ed[tmp] = i ;
	}
	
	vct<pll> seg ;
	
	for(auto it : num){
		seg.pb({st[it] , ed[it]}) ;
	}
	
	merge(seg) ;
	
	cout << quick_pow(2 , seg.size() - 1 , 998244353) ;
	
}
//并查集做法
/*
将一个区间所有点放到其右端点
注意 1xxx2xxx1xx2 是一个区间的特殊情况
*/
int find(int u , vct<int> &fa){
	return fa[u] = fa[u] == u ? u : find(fa[u] , fa) ;
}
aisle
void solve2(){
	cin >> n ;
	vct<int> fa(n + 1 , 0) ;
	vct<int> a(n + 1 , 0) ;
	vct<int> nxt(n + 1 , 0) ;
	map<ll , int> pre ;
	rep(i , 1 , n) cin >> a[i] ;
	rep(i , 1 , n) fa[i] = i ;
	
	drep(i , 1 , n){
		if(!pre[a[i]]){
			pre[a[i]] = i ;
		}else{
			nxt[i] = pre[a[i]] ;
			pre[a[i]] = i ;
		}
	}
	
	ll num = n ;
	int i = 1 ;
	while(i <= n){
		if(!nxt[i]) i ++ ;
		else{
			int j = i ;
			while(j < nxt[i]){
				if(nxt[j] > nxt[i]){
					break ;
				}else{
					int fj = find(j , fa) ;
					int fni = find(nxt[i] , fa) ;
					if(fj == fni) continue ;
					num -- ;
					fa[fj] = fni ;
				}
				j ++ ; 
			}
			i = j ;
		}
	}
	
	cout << quick_pow(2 , num - 1 , 998244353) << "\n" ;
	
} 
小结:

标签:tmp,ed,查集,st,seg,fa,vct,数组,acw4412
来源: https://www.cnblogs.com/tyriis/p/16189017.html