带权并查集

与传统并查集相比,需要维护两点的距离,不能做按秩合并。

1.https://www.luogu.com.cn/problem/P8779

题意概述:给定一个数组 \(a\) 和若干条信息,表示 \(\sum_{l_i}^{r_i} a[i]\) ,随后给定若干询问,包含 \(l\)\(r\),需要输出 \(\sum_{l_i}^{r_i} a[i]\) 的值。

相当于知道一些了前缀和信息 \(pre[r]-pre[l-1]=s\),那么合并 \(r\)\(l-1\),距离为 \(s\)
最后相当于查询 \(r\)\(l-1\) 的距离,如果不属于一个连通分量,显然得不到答案,否则直接输出距离 \(dis[r]-dis[l-1]\) 即可。

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const ll INF = 9e18;

void solve(){
	int n,m,q;
	cin >> n >> m >> q;

	vector<int> p(n+1);
	for (int i=0;i<=n;i++){
		p[i] = i;
	}

	//初始化距离为0
	vector<ll> dis(n+1,0);

	//路径压缩+修正dis
	auto find = [&](int u){
		stack<int> stk;

		int v = u;
		while (v!=p[v]){
			stk.push(v);
			v = p[v];
		}

		//原路径为i1->i2->i3->i4->v
		//dis[v]是正确的,修正dis[i_j]=dis[i_j]+dis[i_j+1]
		int next = v;

		while (!stk.empty()){
			int cur = stk.top();
			stk.pop();

			dis[cur] += dis[next];
			p[cur] = v;
			next = cur;
		}

		return v;
	};

	//合并节点为u->v
	auto unite = [&](int u,int v,ll w){
		int ru = find(u);
		int rv = find(v);

		if (ru==rv) return;
		dis[ru] = dis[v]-dis[u]+w;
		p[ru] = rv;
	};

	//如果不属于同一连通分量,则没有距离关系
	auto query = [&](int u,int v){
		if (find(u)!=find(v)){
			return INF;
		}

		return dis[u]-dis[v];
	};


	for (int i=0;i<m;i++){
		int l,r;
		ll s;
		cin >> l >> r >> s;

		unite(r,l-1,s);
	}


	while (q--){
		int l,r;
		cin >> l >> r;

		ll res = query(r,l-1);

		if (res==INF){
			cout << "UNKNOWN" << '\n';
		}
		else{
			cout << res << '\n';
		}
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int t = 1;
	// cin >> t;
	while (t--) solve();

	return 0;
}

2.https://leetcode.cn/problems/incremental-even-weighted-cycle-queries/description/

题意概述:给定一张无向图,初始没有边。按顺序添加边,如果添加后图中每个环的所有边权值之和仍为偶数,则添加成功,否则失败。最后输出添加成功的边的数量。

对于每条边 \([u,v,w]\),如果 \(u\)\(v\) 不属于一个连通分量,则不会成环,直接添加则可。否则查询一下 \(u\)\(v\) 的距离,加上 \(w\) 之后仍为偶数就添加,否则就不加。
另外我们只关心奇偶性,全部用异或运算即可。


class Solution {
public:
    int numberOfEdgesAdded(int n, vector<vector<int>>& edges) {
        vector<int> p(n),dis(n,0);
        iota(p.begin(),p.end(),0);

        auto find = [&](int u){
            int v = u;
            stack<int> stk;

            while (p[v]!=v){
                stk.push(v);
                v = p[v];
            }

            int next = v;
            while (!stk.empty()){
                int cur = stk.top();
                stk.pop();

                dis[cur]^=dis[next];
                p[cur] = v;
                next = cur;
            }

            return v;
        };

        auto unite = [&](int u,int v,int w){
            int ru = find(u);
            int rv = find(v);

            if (ru==rv){
                if ((dis[u]^dis[v]^w)==0){
                    return true;
                }              
                else{
                    return false;
                }  
            }
            
            dis[ru] = dis[u]^dis[v]^w;
            p[ru] = rv;

            return true;
        };

        int cnt = 0;

        for (auto& vec:edges){
            int u = vec[0];
            int v = vec[1];
            int w = vec[2];

            if (unite(u,v,w)){
                cnt++;
            }
        }

        return cnt;
    }
};
posted @ 2026-04-13 12:13  kzssCCC  阅读(18)  评论(0)    收藏  举报