在某个节点发送一条信息,信息会发送到每个相邻的节点,之后这些节点又会转发到自己相邻的节点,直到所有直接或间接相邻的节点都收到了信息。
所有发送和接收的节点都会将信息存储下来。一条信息只存储一次。
给出小明连接和测试的过程,请计算出每个节点存储信息的大小。
这题要跟着输入数据一步一步模拟才不容易出错,就是你不能连完边再跑逻辑;
这是最暴力的方法(超时)
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,fa[N],ans[N];
vector<int> g[N];
int find(int u) {return fa[u]==u ? u : fa[u]=find(fa[u]);}
int main() {
scanf("%d%d", &n,&m);
for (int i=1; i<N; i++) fa[i]=i;
while (m--) {
int t,u,v; scanf("%d%d%d", &t,&u,&v);
if (t==1) {
fa[find(u)]=find(v);
} else {
int fu=find(u);
for (int i=1; i<=n; i++) if (find(i)==fu)
ans[i]+=v;
}
}
for (int i=1; i<=n; i++) printf("%d ",ans[i]);
return 0;
}
优化思路
先让一个附加的公共根统率一堆连通块的结点,初始情况下发送数据包时只让这个公共根存储,最后树形遍历的时候,就让公共根发送自己存储的数据包给子节点存储
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,fa[N],d[N];
vector<int> g[N];
int find(int u) {return fa[u]==u ? u : fa[u]=find(fa[u]);}
void dfs(int u, int fa) {
d[u]+=d[fa];
for (int v : g[u]) if (fa!=v)
dfs(v,u);
}
int main() {
std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin>>n>>m;
int root=n+1;
for (int i=1; i<N; i++) fa[i]=i;
for (int i=0; i<m; i++) {
int op,u,v; cin>>op>>u>>v;
if (op==1) {
int fu=find(u), fv=find(v);
if (fu!=fv) {
fa[fu]=fa[fv]=root;
g[root].push_back(fu);
g[root++].push_back(fv); //每次只要两个点不在一个连通块上,就新开一个连通块;这样既可保证未连接的点收不到"别人"发的数据,又可保证后面的点合并之后,数据的可接受性,且只接受后面合并后发送的数据
}
} else {
d[find(u)]+=v;
}
}
for (int i=n+1; i<root; i++) if (fa[i]==i) dfs(i,0); //如果i是根,则将i的数据扩散到i的子节点
for (int i=1; i<=n; i++) printf("%d ", d[i]);
return 0;
}
更优的做法是:用带权并查集(用的还不是很熟),复杂度是 mlogn