并查集

并查集

用一个索引代表父节点,如果根一样就是一个集合。查找的时候使用路径压缩提升效率。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

int P[100100];

int findroot(int x){
    if(P[x] != x) P[x]=findroot(P[x]);//这里路径压缩提升了效率,直接把P[x]更新为上一个,不用反复找了!
    return P[x];
}

void merge(int a, int b){
    //找到根
    int roota, rootb;
    roota = findroot(a);
    rootb = findroot(b);
    if(roota!=rootb){
        P[roota] = rootb;//把a的根换成b的根,如果是同一个集合就不管了
    }
}

void query(int a, int b){
    int roota, rootb;
    roota = findroot(a);
    rootb = findroot(b);
    if(roota!=rootb)cout << "No" << endl;
    else cout << "Yes" << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m;
    cin >> n >> m;
    for (int i = 0; i < n+1; i ++ ){
        P[i]=i;//初始化指向自己的是根
    }
    int a,b;
    char op;
    while (m -- ){
        cin >> op >> a >> b;
        if(op=='M')merge(a,b);
        else if(op=='Q')query(a,b);
    }
    return 0;
}

联通块的数量

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int P[100100];
int n;
int s[100100]={0};
int find(int a){
    if(P[a]!=a) P[a]=find(P[a]);
    return P[a];
}

void connect(int a, int b){
    if(a==b)return;
    int roota = find(a);
    int rootb = find(b);
    if(roota!=rootb){P[roota]=rootb;s[rootb]+=s[roota];}//将a的连通量加到b的
}

void queryc(int a, int b){
    int roota = find(a);
    int rootb = find(b);
    if(roota==rootb)cout << "Yes" << endl;
    else cout << "No" << endl;
}

void queryn(int a){
    int roota = find(a);
    //for (int i = 0; i < n+1; i ++ ){
    //    if(find(P[i])==roota)c++;
    //}//这样太慢了直接维护一个size集合会更快!
    cout << s[roota] << endl;//直接输出s数量
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int m;
    cin >> n >> m;
    for (int i = 0; i < n+1; i ++ ){
        P[i]=i;//指向自己表示是根
        s[i] = 1;
    }
    string op;
    int a,b;
    while (m -- ){
        cin >> op;
        if(op=="C"){
            cin >> a >> b;
            connect(a,b);
        }
        else if(op=="Q1"){
            cin >> a >> b;
            queryc(a,b);
        }
        else if(op=="Q2"){
            cin >> a;
            queryn(a);
        }
    }
    return 0;
}

食物链

使用带权并查集,使用向量思维!把每个节点看成向量加减。

#include <iostream>
#include <cstring>
#include <algorithm>
//带权并查集,向量思维
using namespace std;

int P[100100];
int V[100100];

int find(int a){
    int ofather=0;
    if(P[a]!=a){
        ofather=P[a];
        P[a] = find(P[a]);
        V[a] = (V[ofather] + V[a])%3;
    }
    return P[a];
}

void same(int a,int b){
    int roota=find(a);
    int rootb=find(b);
    if(roota!=rootb){
        P[roota] = rootb;
        V[roota] = (V[b] - V[a] + 3)%3;//只需更新roota的值其他是find处理
    }
}

void eat(int a, int b){
    int roota=find(a);
    int rootb=find(b);
    if(roota!=rootb){
        P[roota] = rootb;
        V[roota] = (V[b]-V[a]+1+3)%3;//只需更新roota的值其他是find处理
    }
}

int queryconn(int a, int b){
    int roota=find(a);
    int rootb=find(b);
    return roota==rootb;
}

int query(int a,int b){
    return (V[a]-V[b]+3)%3;//返回0说明没有eat关系
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,k;
    cin >> n >> k;
    for (int i = 0; i < n+1; i ++ ){
        P[i]=i;
    }
    int c=0;
    int op,a,b;
    while (k -- ){
        cin >> op >> a >> b;
        if(a>n||b>n){c++;continue;}
        if(op==2&&a==b){c++;continue;}
        if(op==1){
            if(queryconn(a,b)&&query(a,b)!=0){c++;continue;}//不是0不是同类关系
            same(a,b);
        }
        else if(op==2){
            if(queryconn(a,b)&&query(a,b)!=1){c++;continue;}//不是1不是吃的关系
            eat(a,b);
        }
    }
    cout<< c<<endl;
    return 0;
}
posted @ 2025-08-01 20:13  .N1nEmAn  阅读(10)  评论(0)    收藏  举报