一、 带权并查集的found 的函数:
found函数找父亲的同时,可以维护关系
int found(int x)
{
if(par[x] == x)return par[x];
else
{
int t;
t = par[x];
par[x] = found(par[x]);
value[x] += value[t];
return par[x];
}
}
二、带权并查集的难点(合并)
对于带权并查集难就难在 合并时 关系的处理。
如果x,y不在一个集合, 现在 知道了x ,y 的关系。 然后要合并x ,y所在的集合。
①先合并:就是rootx 指向y。
②然后处理 rootx与y的关系:
知道rootx与y的关系 == rootx与 x 的关系 + x与y的关系。
因此要通过x与rootx的关系 求出逆关系, 即rootx与x 的关系。
相关题:
最简单的, 模板题
HihoCoder - 1515
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn = 1e5+50;
int par[maxn];
int r[maxn];
void init(int N)
{
memset(r, 0, sizeof(r));
for(int i = 1;i <= N;i++)
{
par[i] = i;
}
}
int found(int x)
{
if(par[x] == x)return par[x];
else
{
int t = par[x];
par[x] = found(par[x]);
r[x] += r[t];
return par[x];
}
}
void Union (int x, int y, int s)
{
int rootx = found(x);
int rooty = found(y);
if(rooty!= rootx)
{
par[rootx] = y;
r[rootx] = (s - r[x]);/**将 x 与 y的关系 转换为 rootx 与 y 的 关系*/
}
}
void input(int N, int M)
{
init(N);
for(int i = 1;i <= M;i++)
{
int x, y, s;
scanf("%d %d %d", &x, &y, &s);
Union(x, y, s);
}
}
void query(int Q)
{
while(Q--)
{
int x, y;
scanf("%d %d", &x, &y);
if(found(x)!= found(y))
{
printf("-1\n");
}
else
{
printf("%d\n", r[x] - r[y]);
}
}
}
int main()
{
int N, M, Q;
scanf("%d %d %d", &N, &M, &Q);
input(N, M);
query(Q);
return 0;
}
poj 1812 食物链
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn = 5e4+500;
int par[maxn];// 并查集 父亲数组
int r[maxn];//权值 表示食物链之间的关系
void init(int N)
{
memset(r, 0, sizeof(r));
for(int i = 1;i <= N;i++)
{
par[i] = i;
}
}
int found(int x)
{
if(par[x] == x)return par[x];
else
{
int t = par[x];
par[x] = found(par[x]);
r[x] = (r[x]+r[t])%3;
return par[x];
}
}
void Union(int x, int y, int rel)
{
int rootx = found(x);
int rooty = found(y);
par[rooty] = rootx;
if(rel == 1)rel = 0;// rel 等于 1 y 对 x的 关系 为 0
else rel = 1;/****rel 等于 2 x吃y y对x 就是 1(y被 x吃)***/
r[rooty] = (r[x] + rel + (3-r[y]) )%3;/****rooty 跟根的关系就是 x 根rootx 的关系 + y根x的关系 + rooty 跟y的 关系 mod 3*******/
}
int main()
{
int N, K, cnt = 0;
scanf("%d %d", &N, &K);
init(N);
while(K--)
{
int rel, x, y;
scanf("%d %d %d", &rel, &x, &y);
if(x > N || y > N)cnt++;
else if(rel == 2 && x == y)cnt++;
else if(found(x) == found(y))
{
if(rel == 1 && r[x]!= r[y])cnt++;
else if(rel == 2 &&r[x]!= (r[y]+2)%3)cnt++;
}
else
{
Union(x, y, rel);
}
}
printf("%d",cnt);
return 0;
}