并查集

并查集

板子

struct DSU{
	int num;
	vector<int> fa, sz;
	DSU(int x) : num(x), fa(x + 1), sz(x + 1, 1){
		for(int i = 0; i <= x; ++ i){
			fa[i] = i;
		}
	}
	int size(int x){ return sz[findfa(x)]; }
	int findfa(int x){
		while(x != fa[x]) x = fa[x] = fa[fa[x]];
		return x;
	}
	bool same(int x, int y){ return findfa(x) == findfa(y); }
	bool merge(int x, int y){
		x = findfa(x); y = findfa(y);
		if(x == y) return false;
		sz[x] += sz[y];
		fa[y] = x;
		return true;
	}
};

相关资料

oi wiki - dsu
并查集 --算法竞赛专题解析(3)


例题

2023ACM暑假训练day 2 并查集


带权并查集

我们可以在并查集的边上定义某种权值、以及这种权值在路径压缩时产生的运算,从而解决更多的问题

例题2道

1.hdu 3038 How Many Answers Are Wrong
利用带权并查集解决这个问题则非常简单
具体思想非常值得理解!!!

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
#define debug(x) cout << #x << " = " << x << endl
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << endl
//#define int long long

using namespace std;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ull,ull> pull;
typedef pair<double,double> pdd;
/*
带权并查集
*/
const int maxm=2e5+5,inf=0x3f3f3f3f,mod=998244353;
int n,m,fa[maxm],d[maxm],ans;

int findfa(int x){
	if(fa[x]!=x){
		int t=fa[x];//记下原父节点,等会更新
		fa[x]=findfa(fa[x]);
		d[x]+=d[t];//更新从节点x到根的距离
	}
	return fa[x];
}

void merge(int a,int b,int c){
	int x=findfa(a),y=findfa(b);
	if(x==y){
		if(d[a]-d[b]!=c) ++ans;//区间差不为c时说明当前给定的数据是假的
	}else{
		fa[x]=y;
		d[x]=d[b]+c-d[a];//此处更新的是d[x],不是d[b]。因为x不作为终点了
	}
	return ;
}

void pre(int x){
	for(int i=0;i<=n;++i){
		fa[i]=i;
		d[i]=0;
	}
	ans=0;
	return ;
}

void solve(){
	while(cin>>n>>m){
		pre(n);
		int a,b,c;
		for(int i=0;i<m;++i){
			cin>>a>>b>>c;
			--a;
			merge(a,b,c);
		}
		cout<<ans<<'\n';
	}
	return ;
}

signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _=1;
//	cin>>_;
	while(_--){
		solve();
	}
	return 0;
}

2.poj 1182 食物链
具体思路见中间罗老师的链接
本题的权值不是简单的相加
关键两点就是路径压缩时,怎么改变权值;合并时,怎么改变权值;如何判断矛盾。
这就是本题的三个关键之处

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
#define debug(x) cout << #x << " = " << x << endl
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << endl
//#define int long long

using namespace std;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ull,ull> pull;
typedef pair<double,double> pdd;
/*

*/
const int maxm=5e4+5,inf=0x3f3f3f3f,mod=998244353;
int n,k,ans,fa[maxm],d[maxm];

void pre(){
	ans=0;
	for(int i=0;i<=n;++i) fa[i]=i;
	return ;
}

int findfa(int x){
	if(x!=fa[x]){
		int t=fa[x];
		fa[x]=findfa(fa[x]);
		d[x]=(d[x]+d[t])%3;
	}
	return fa[x];
}

void merge(int c,int a,int b){
	int x=findfa(a),y=findfa(b);
	if(x==y){
		if(c - 1 != ((d[a] - d[b] + 3) % 3)) ++ans;
	}else{
		fa[x]=y;
		d[x]=(d[b]-d[a]+c-1)%3;
	}
	return ;
}

void solve(){
	cin>>n>>k;
	pre();
	int c,a,b;
	for(int i=0;i<k;++i){
		cin>>c>>a>>b;
		if(a>n||b>n||c==2&&a==b) ++ans;
		else merge(c,a,b);
	}
	cout<<ans<<'\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _=1;
//	cin>>_;
	while(_--){
		solve();
	}
	return 0;
}
posted on 2023-06-28 23:02  Qiansui  阅读(4)  评论(0编辑  收藏  举报