并查集

基本思路:用于合并同类项,路径压缩使得它的时间复杂度极低

并查集的核心,用于寻找祖先:
int find(int x) { if (p[x] != x) { p[x] = find(p[x]); } return p[x]; }

用于合并(易错点是合并一定要合并祖先而非本人)
void merge(int a, int b) { int pa = find(a); int pb = find(b); if (pa != pb) { p[pa] = pb; } }

拆点并查集(反集),用于放敌人,即合并‘不可以在一起的异类’
void uunion(int u, int v) { u = find(u); v = find(v); if (u == v) { return; } pp[u] = v; } //以下两行是main函数中 uunion(p[i].a + N, p[i].b); uunion(p[i].a, p[i].b + N);

以及来自食物链(NOI)的带权并查集,其中d[N]记录权重
`
const int N = 50010;
int p[N], d[N];

int find(int x){
if (p[x] != x){
int t = find(p[x]);//不能直接把p[x]=find(p[x]),因为后面d[p[x]]还要用p[x]
d[x] += d[p[x]];
p[x] = t;
}
return p[x];
}

int main()
{
int n,m;cin>>n>>m;
for (int i = 1; i <= n; i ++ ) p[i] = i;
int res = 0;
while (m -- )
{
int t, x, y;scanf("%d%d%d", &t, &x, &y);
if (x > n || y > n) res ++ ;
else{
int px = find(x), py = find(y);
if (t == 1)
{
if (px == py && (d[x] - d[y]) % 3) res ++ ;
else if (px != py)
{
p[px] = py;
d[px] = d[y] - d[x];//因为(d[x]+d[px]-d[y])%3==0,所以d[x]+d[px]-d[y]=0,移项可得
}
}
else {
if (px == py && (d[x] - d[y] - 1) % 3) res ++ ;
else if (px != py) {
p[px] = py;
d[px] = d[y] + 1 - d[x];
}
}
}
}
cout<<res;return 0;
}
`

posted @ 2025-08-16 21:25  yubai111  阅读(7)  评论(0)    收藏  举报