https://www.acwing.com/problem/content/description/2071/

每次合并的时候需要开一个新点去实现信息的无后效性,也就是合并之前的两个连通块信息是无法共享的,发现这样开点连边最后

形成一棵树,每次我们将信息传递到新点,也是两个合并点的lca,这使得最后求答案的直接求一边树上前缀和,不同子树不受影响

debug:最后合并n-1次,初始化和空间都要开两倍

// Problem: 网络分析
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/2071/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
//# define int long long
#define ull unsigned long long
#define pii pair<int,int>

#define baoliu(x, y) cout << fixed << setprecision(y) << x
#define endl  "\n"
#define debug1(x) cerr<<x<<" "
#define  debug2(x) cerr<<x<<endl
const int N = 2e4 + 10;
const int M = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
const double eps = 1e-8;
int n, m;
int a[N];
int fa[N];
int sz[N];
vector<int>e[N];

int find(int x){
	if(x!=fa[x])fa[x]=find(fa[x]);
	return fa[x];
}
//并不是简单并查集,因为还涉及信息的历史性,也就是后来进入的节点是没有办法享用之前
//的信息的
//动态开点并查集+树上差分?

void dfs(int u,int fa){
	sz[u]+=sz[fa];
	for(auto v:e[u]){
		if(v==fa)continue;
		dfs(v,u);
		//sz[v]+=sz[u];
	}
}
void solve(){
	//for(int i=1;i<=n;i++)fa[i]=i;
	cin>>n>>m;
	int root=n+1;
		for(int i=1;i<=n*2;i++)fa[i]=i;
	for(int i=1;i<=m;i++){
		int op;cin>>op;
		if(op==1){
			int u,v;cin>>u>>v;
			u=find(u),v=find(v);
			if(u==v)continue;
			fa[u]=fa[v]=root;
			
			e[root].push_back(u);
			e[root].push_back(v);
			root++;
		}
		else {
			int v;cin>>v;
			v=find(v);
			int val;cin>>val;
			sz[v]+=val;
		}
	}
	for(int i=1;i<=2*n;i++){
		if(fa[i]==i)dfs(i,0);
	}
	for(int i=1;i<=n;i++)cout<<sz[i]<<" ";
}
int main() {
    cin.tie(0);
    
    ios::sync_with_stdio(false);

    int t;
   //cin>>t;
     t=1;
    while (t--) {
solve();
    }
    return 0;
}

``