标签:带权并查集 之间 namespace 公式 cpp 保存 space c++ i++
第一次接触带权并查集
//带权并查集 更新父节点的同时更新权值
#include<bits/stdc++.h>
using namespace std;
const int N = 200020;
int pre[N];
int cnt[N];//cnt[i]代表i到自己祖先的权值
int Find(int x) {//路径压缩,更新父节点和权值
if (x != pre[x]) {
int fa = pre[x];
pre[x] = Find(pre[x]);
//当合并祖先时,x到新祖先的权值等于x到旧祖先的权值加旧祖先到新祖先的权值(此处的cnt[x]还没更新到结点所以还是到旧祖先的权值)
cnt[x] += cnt[fa];
}
return pre[x];
}
int main() {
int n, m, x, y, w, s;
while (scanf("%d%d", &n, &m) != EOF) {
s = 0;
for (int i = 0; i <= n; i++) {
pre[i] = i;
cnt[i] = 0;
}
while (m--) {
scanf("%d%d%d", &x, &y, &w);
int fx = Find(x - 1);//因为[a, b]中包含a,所以实际上是对(a, b]操作,即x = x-1
int fy = Find(y);
//cout << "fx = " << fx << " fy = " << fy << endl;
if (fx == fy) {//如果发现该区间的权值和之前得出的权值不等,s++
if (cnt[x - 1] + w != cnt[y])
s++;
}
/*
在合并操作中,对我们需要更新cnt[fb](由于fy成为fa的子节点),公式:cnt[fy] = cnt[x - 1] - cnt[y] + w
- 更新cnt[fy]的目的是维护子树(fy)相对于父亲树(fx)之间的权值差。
- cnt[y]保存结点y到结点fy之间的权值; cnt[x-1]保存结点x-1到结点fx之间的权值;w是结点x-1到结点y之间的权值
- 所以cnt[fy]的值=从结点fa到结点x-1的权值(+cnt[x - 1]),加上从结点x到结点y的权值(+w),最后减去结点fy到结点y的权值(-cnt[y])
*/
else {
pre[fy] = fx;
//cout << "pre[fy] = " << pre[fy] << endl;
cnt[fy] = cnt[x - 1] + w - cnt[y];
//cout << "cnt[fy] = " << cnt[fy] << endl;
}
}
printf("%d\n", s);
}
return 0;
}
#3038:How Many Answers Are Wrong (带权并查集)
标签:带权并查集 之间 namespace 公式 cpp 保存 space c++ i++
原文地址:https://www.cnblogs.com/RioTian/p/12874867.html