并查集杂题
并查集杂题
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;
}