带权并查集
与传统并查集相比,需要维护两点的距离,不能做按秩合并。
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;
}
};

浙公网安备 33010602011771号