Codeforces 1850H:The Third Letter 带权并查集

1850H.The Third Letter


Description:

  • n 个人,m 个条件,每次给出两个人 aibi 一维的位置关系,以距离 di 表示,其正负表示方位的前后,判断这 m 个条件是否矛盾。(不同的人可以在横轴上位于同一点)

Analysis:

  • 将所有的横轴位置抽象为一个点,用带权并查集维护点与点之间的链接关系。
  • 对于一般的并查集来说,可以维护集合内的联通关系,进而求解不同集合之间的问题(如计数等)或判断图的联通性。带权并查集主打一个边权的维护(即额外的信息)。
  • 路径压缩DSU 的重要一环,相当于建立起每个子节点和根节点的直接关系,这便优化了查找效率,无须从某一节点持续向上递归(一旦树退化成了一条链,岂不是寄了!!)
int find(int x) {
	if(x != fa[x]) fa[x] = find(fa[x]);
	return fa[x];
	// return fa[x] = find(fa[x]) 
}
  • 那带权并查集呢?注意,我们要维护的不是题中所给的 d,而是要动态维护起每个点到其父节点(在路径压缩下也就是根节点)的 w[i],这里就产生了对根节点有影响的两个过程:
  1. findx)过程:因路径压缩,节点 x 原来的 fa[x] 更新为根节点,那么 w[x] 记录的子节点到父节点的距离 也要相应更新为到根节点(也就是新的父节点)
  2. 合并过程:因集合合并,两个集合各自的根节点变为一个大集合的一个根节点,自然而然,其中一个集合要进行权值的更新。

image
image


Solution:

int fa[maxn];
ll w[maxn];
 
int find(int x) {
	if(x != fa[x]) {
		// 记录原来的父节点,从而记录原来的父节点 t 到根节点的距离w[t]
		int t = fa[x];
		fa[x] = find(fa[x]);
		w[x] += w[t]; // 路径压缩的权值更新
	}
	return fa[x];
}
 
void solve() {
	int n,m; cin >> n >> m;
	// 初始化
	for(int i=1;i<=n;i++) {
		fa[i] = i; // 我是我的父亲
		w[i] = 0;  // 到父节点(目前是自己)的距离
	}
	bool flag = true; // 标记目前是否已经出现矛盾
	while(m--) {
		int u,v; ll d;
		cin >> u >> v >> d;
		if(!flag) continue;
		
		int fu = find(u);
		int fv = find(v);
		if(fu != fv) {
			fa[fu] = fv;
			w[fu] = d + w[v] - w[u]; //集合合并的权值更新
		}
		else { // fu == fv 说明二者距离可求,与所给的d比较即可
			if(w[u] - w[v] != d) flag = false;
		}
	}
	if(flag) cout << "YES" << endl;
	else cout << "NO" << endl;
}
posted @   Trilliverse  阅读(88)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示