2020年第十一届蓝桥杯省赛J-网络分析(带权并查集)
acwing评测地址:https://www.acwing.com/problem/content/description/2071/
解析:
如果每次操作2,都要对修改点的所在树都修改一遍,显然是很慢的。
那么定义一个d[],d[i]表示i点与根节点之间的信息量差值,定义now[i],表示i点本身的信息量。
举个例子:
复杂度大概是O(log*n)
这样就不用每次操作就把块中每个点都加。询问结束后跑一遍就行了。
当一个点的根节点改变时,它对应的d[]也是要变的。即:
int find(int x) { if(x!=pr[x]) { int md=pr[x]; pr[x]=find(pr[x]);//路径压缩 d[x]+=d[md]; //<---这里。 } return pr[x]; }
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn = 1e4 + 5; int pr[maxn],d[maxn],now[maxn]; int n,m; void init(){ for(int i=1;i<=n;i++)pr[i]=i; } int find(int x) { if(x!=pr[x]) { int md=pr[x]; pr[x]=find(pr[x]); d[x]+=d[md]; } return pr[x]; } int main() { scanf("%d%d",&n,&m); init(); while(m--) { int x,a,b; scanf("%d%d%d",&x,&a,&b); if(x==1) { if(a==b) continue; int f1=find(a),f2=find(b); if(f1!=f2) { pr[f2]=f1; d[f2]=now[f2]-now[f1]; } } else { int fa=find(a); now[fa]+=b; } } for(int i=1;i<=n;i++) cout<<now[find(i)]+d[i]<<" "; cout<<endl; }