2020牛客暑期多校 I Interesting Computer Game (并查集+离散化)

I Interesting Computer Game
题意:
有两个数组a , b , 第i步可以从ai bi 中选取一个数,求出最多能获取几个不同的数字 。
下面直接上AC代码:
并查集+离散化

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<b;i++)	
#define T int t ;cin >> t;while(t--)
using namespace std ;
typedef long long ll;
typedef unsigned long long ull;
inline ll gcd(ll a,ll b){return b == 0? a:gcd(b, a % b);}
inline ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll Mode(ll a, ll b, ll mode)    {ll sum = 1;if(mode == 1)return 0 ;while (b) {if (b & 1) {sum = (sum * a) % mode;b--;}b /= 2;a = a * a % mode;}return sum;}
const int maxn = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-11;
const ll mod = 1e9 + 7;
ll a[maxn], b[maxn];
ll pre[maxn] ,vis[maxn] ,c[maxn];
ll tot ,n,ans ;
ll find(ll x)
{
	if(pre[x] == x)
		return x ;
	else
		return pre[x] = find(pre[x]) ;
}
void merge(ll i, ll j)
{
	ll x =  find(i) ;
	ll y = find(j) ;
	if(x == y)
	{
		vis[x] = 1 ;//如果之前已经联通了,现在再加一条边,那么连通块的边数肯定不低于点数了,那么标记一下祖先
		return ;
	}
    pre[x] = y ;
    if(vis[x]) vis[y] =1 ;
}
void solve()
{
	scanf("%lld",&n) ;
	tot = 0 ;
	for(int i = 1 ; i <= n ; i++){
		scanf("%lld%lld",&a[i],&b[i]) ;
		c[++tot] = a[i] ;
		c[++tot] = b[i] ;
	}
	for(int i = 0 ; i <= maxn ;i++){		//并查集初始化 
		pre[i] = i ;
		vis[i] = 0 ;
	}
	sort(c+1,c+1+tot) ;
	for(int i = 1 ; i<= n ;i++){		//离散化 
		a[i] = lower_bound(c+1,c+tot+1,a[i]) - c ;
		b[i] = lower_bound(c+1,c+tot+1,b[i]) - c ;
		merge(a[i],b[i]) ;
	}
	ans = tot ;
	for(int i = 1 ; i <= tot ; i++){		//注意,这里离散化已经完成,不再是1-n 而是1-tot
		if(vis[i] == 0&& pre[i] == i)
			ans-- ;
	}
}
int main() 
{
    int Case;
    cin >> Case;
    int x = Case ;
    while (Case--) {
        solve();
        printf("Case #%d: %lld\n",x-Case,ans) ;
    }
    return 0;
}

  • 下面附上知识点的补充(lower_bound和upper_bound):

lower_bound( )和upper_bound( )都是利用二分查找的方法在一个排好序的数组中进行查找的。
在从小到大的排序数组中,
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

猜你喜欢

转载自blog.csdn.net/zcmuhc/article/details/107800378