并查集杂题

并查集杂题

P1525 [NOIP2010 提高组] 关押罪犯

带权并查集 相比于食物链维护同类 天敌 猎物三个集合 本题弱化为只需要维护敌人和朋友 敌人为\(x+n\)点 本身为\(x\)

影响值从大到小地加 将犯人贪心地分到两个监狱中 如果实在没办法了 那么直接结束程序输出当前影响值即可

注意并查集要加到\(2*n\)

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define mid (l+r>>1)
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;
const int mod = 100003;
const int N = 1e5 + 5;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
//#define getchar() cin.get();
int read()
{
	int x = 0 , f = 1;
	char ch = getchar();
	while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f ;
}

int n , m , dis[N] , fa[N];

int find ( int x ) { return x == fa[x] ? x : fa[x] = find(fa[x]); }

struct node { int u , v , w; } e[N];

inl void merge ( int x , int y ) 
{
	int fx = find(x) , fy = find(y);
	if ( fx != fy ) fa[fx] = fy;
}

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr) , cout.tie(nullptr);
	n = read() , m = read();
	for ( int i = 1 ; i <= 2 * n ; i ++ ) fa[i] = i;
	for ( int i = 1 ; i <= m ; i ++ ) e[i].u = read() , e[i].v = read() , e[i].w = read();
	sort ( e + 1 , e + m + 1 , [](const node &a , const node &b) { return a.w > b.w; } );
	for ( int i = 1 ; i <= m ; i ++ )
	{
		int fu = find(e[i].u) , fv = find(e[i].v);
		if ( fu == fv ) return cout << e[i].w << endl , 0;
		merge ( e[i].u , e[i].v + n );
		merge ( e[i].u + n , e[i].v );
	}
	cout << 0 << endl;
	return 0;
}

[ABC279F] BOX

不能像正常并查集一样维护 因为老的盒子是需要清空的

所以设置两个数组\(ans[N] , id[N]\) 分别表示并查集中\(i\)盒子节点对应的原来编号 原来的第\(i\)个盒子对应的并查集节点 这两个数组互为映射关系

其余操作类似正常并查集

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define mid (l+r>>1)
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define eb emplace_back
#define mkp make_pair
const int N = 1e6 + 5;
const int inf = 0x3f3f3f3f;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
//#define getchar() cin.get();
int read()
{
	int x = 0 , f = 1;
	char ch = getchar();
	while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f ;
}
int n , q , ans[N] , id[N] , fa[N] , cntball , cntbox;
//并查集中i盒子节点对应的原来编号 原来的第i个盒子对应的并查集节点
int find ( int x ) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
inl void merge ( int x , int y )
{
	int fx = find(x) , fy = find(y);
	if ( fx != fy ) fa[fy] = fx;
}

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr) , cout.tie(nullptr);
	n = read() , q = read();
	cntball = n , cntbox = n + q;
	for ( int i = 1 ; i <= n + 2 * q ; i ++ ) fa[i] = ans[i] = id[i] = i;
	for ( int i = 1 , op , x , y ; i <= q ; i ++ )
	{
		op = read();
		if ( op == 1 )
		{
			x = read() , y = read();
			merge ( id[x] , id[y] );
			++ cntbox , id[y] = cntbox , ans[cntbox] = y; 
		}
		else if ( op == 2 ) merge ( id[read()] , ++cntball );
		else cout << ans[find(read())] << endl;
	}
	return 0;
}

[ABC295G] Minimum Reachable City

很巧妙的题 读入的东西构成了树结构 然后加边操作实际上相当于让树上的两个节点构成了一个环

那么对于每次操作 将\(v\)\(u\)之间的所有节点向它所属并查集根节点的父节点连边 也就是相当于让这一条路径上的所有节点归属于\(v\)这个节点的集合中

\(53ms\)代码:

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define mid (l+r>>1)
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define eb emplace_back
#define mkp make_pair
const int N = 2e5 + 5;
//char buf[1<<24] , *p1 , *p2;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
#define getchar() cin.get();
int read()
{
	int x = 0 , f = 1;
	char ch = getchar();
	while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f ;
}

int fa[N] , n , q , p[N];

int find ( int x ) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
inl void merge ( int x , int y )
{
	int fx = find(x) , fy = find(y);
	if ( fx != fy ) fa[fy] = fx;
}

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr) , cout.tie(nullptr);
	n = read();
	for ( int i = 2 ; i <= n ; i ++ ) p[i] = read();
	for ( int i = 1 ; i <= n ; i ++ ) fa[i] = i;
	q = read();
	while ( q -- )
	{
		int op = read() , u , v;
		if ( op == 1 )
		{
			u = read() , v = read() , u = find(u);
			while ( u > v ) merge ( p[u] , u ) , u = find(u);
		}
		else u = read() , cout << find(u) << endl;
	}
	return 0;
}

其实暴力一个一个跳父亲也是可以的 没有被卡(\(807ms\)):

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define mid (l+r>>1)
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define eb emplace_back
#define mkp make_pair
const int N = 2e5 + 5;
//char buf[1<<24] , *p1 , *p2;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
#define getchar() cin.get();
int read()
{
	int x = 0 , f = 1;
	char ch = getchar();
	while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f ;
}

int fa[N] , n , q , p[N];

int find ( int x ) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
inl void merge ( int x , int y )
{
	int fx = find(x) , fy = find(y);
	if ( fx != fy ) fa[fy] = fx;
}

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr) , cout.tie(nullptr);
	n = read();
	for ( int i = 2 ; i <= n ; i ++ ) p[i] = read();
	for ( int i = 1 ; i <= n ; i ++ ) fa[i] = i;
	q = read();
	while ( q -- )
	{
		int op = read() , u , v;
		if ( op == 1 )
		{
			u = read() , v = read() , u = find(u);
			while ( u > v ) merge ( p[u] , u ) , u = p[u];
		}
		else u = read() , cout << find(u) << endl;
	}
	return 0;
}
posted @ 2023-08-06 11:31  Echo_Long  阅读(10)  评论(0编辑  收藏  举报