2020第十一届蓝桥杯7月省赛J题
试题 J: 网络分析
题目描述:
本题思路:这道题是一个带权并查集,当初一看到这个题目的时候应该就要想到并查集,因为有权值的存在,所以我们可以想到带权并查集。
我们如果普通维护当前结点与父结点之间的关系的话,很明显非常难维护,但是如果我们维护当前结点与祖先结点之间的关系的话,那就会好很多,我们每次把更新操作都在祖先结点上面做,然后我们维护一个当前结点与祖先结点之间的差值,我们最后每个结点的值就是祖先结点的值+差值。
我们在查找祖先结点的时候有路径压缩,所以同时要修改差值d[]。
操作1:合并操作,如果当前操作的两个结点不连通,那么需要更新差值d[]
操作2:直接在祖先结点上面更新即可。
代码部分:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int fa[N], d[N], now[N];
int n, m;
int find(int x)
{
if (x != fa[x])
{
int t = fa[x];
fa[x] = find(fa[x]);
d[x] += d[t];
}
return fa[x];
}
int main()
{
scanf ("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
fa[i] = i;
}
while (m--)
{
int op;
scanf ("%d", &op);
if (op == 1)
{
int a, b;
scanf ("%d%d", &a, &b);
int x = find(a);
int y = find(b);
if (x != y)
{
fa[y] = x;
d[y] = now[y] - now[x];
}
}
else
{
int p, t;
scanf ("%d%d", &p, &t);
int root = find(p);
now[root] += t;
}
}
for (int i = 1; i <= n; i++)
{
int ans = now[find(i)] + d[i];
if (i == 1)
{
cout << ans;
}
else
{
cout << " " << ans;
}
}
cout << endl;
return 0;
}