网络分析

题意

操作 1 :把两个点所在的连通块合并起来
操作 2 :向某个点所在的连通块的所有点累加一个值

思路

联通块合并,基础的并查操作,考虑怎么给某一个点中所有联通块加某个值。我们不能把简单的把这个联通块父节点加一个值,最后处理完,每个点的值+=联通块节点的值,因为,find操作会把父节点换来换去。
当俩个节点,不联通时候:我们开一个新节点,作为这俩节点的父节点。我们每次给这些虚拟节点加权值。为了最后把这些权值放会子节点,我们可以给虚拟节点向子节点连接一条边。最后dfs把虚拟节点的值放回子节点。要注意不能把每个虚拟节点都下放,应该把虚拟节点中跟节点的值开始dfs,因为这样期间会顺带把其他虚拟节点下放。不会重复计算。
在这里插入图片描述
例如这个图,我们只需要吧虚拟根节点开始dfs下放权重,中间会把其他节点信息带下去。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mst(s,_s) memset(s, _s, sizeof(s))
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;
const int N = 1e6+100;
int T,n,m;
int f[N];
int root;
int h[N],ne[N],e[N],idx,val[N];
int find(int x)
{
    return x==f[x]?x:f[x]=find(f[x]);
}
void add(int a,int b)
{
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}

void dfs(int u,int fa)
{
    val[u]+=val[fa];
    for(int i=h[u];~i;i=ne[i])
    {
        int j=e[i];
        
        dfs(j,u);
    }
}
int main() {
    memset(h,-1,sizeof h);
    cin>>n>>m;
    for(int i=1;i<=n+m;i++) f[i]=i;
    root=n+1;
    for(int i=1;i<=m;i++)
    {
        int op,a,b;
        cin>>op>>a>>b;
        if(op==1)
        {
            a=find(a);
            b=find(b);
            if(a!=b)
            {
                f[a]=root;
                f[b]=root;
                add(root,a);
                add(root,b);
                root++;
            }
        }
        else{
            a=find(a);
            val[a]+=b;
        }
    }
    for(int i=n+1;i<=root;i++)
    {
        if(f[i]==i) dfs(i,0);
    }
    for(int i=1;i<=n;i++)
        cout<<val[i]<<' ';



    return 0;
}

 posted on 2020-10-10 00:16  谁是凶手1703  阅读(106)  评论(0)    收藏  举报