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;
}
posted @ 2020-10-15 09:10  liyexin  阅读(391)  评论(0编辑  收藏  举报