G Operating on a Graph(并查集)

题目链接


题目大意:

给你一个图,有 n个点,m条边,点的下标[0,n-1],对于点i,其开始时属于 i−group 总共操作 q次,每次操作时给出一个 n ,如果n的group不是n则不操作,否则将所有与 n−group 直接相连的 group 加入到 n−group中在所有操作结束后,求每个点所在的 group

解题思路:

看到group就想到用并查集,用vector存取每个相邻点的信息,只要团相邻就合并,这里要用到启发式合并,否则会超时

代码:

#include

using namespace std;

const int maxn = 8e5+5;
typedef long long ll;
typedef pair<int,int> pii;
int n,m;
int f[maxn];
vector<int> e[maxn];


template <typename T>inline void read(T& t){
    char c=getchar();t=0;
    int f=1;
    while(!isdigit(c)){
        if(c=='-')f=-1;
        c=getchar();
    }
    while(isdigit(c))t=t*10+c-48,c=getchar();
    t=f*t;
}

template <typename T,typename... Args> inline void read(T& t,Args&... args){
    read(t);read(args...);
}

int find(int x){
    return f[x]==x?x:f[x]=find(f[x]);
}

void pb(vector<int> &x,vector<int> &y){
    if(x.size()<y.size()){
        swap(x,y);
    }
    for(auto it:y){
        x.emplace_back(it);
    }
}

int main(){
    int t;
    read(t);
    while(t--){
        read(n,m);
        for(int i=0;i<=n;i++){
            f[i]=i;
            e[i].clear();
        }
        for(int i=1;i<=m;i++){
            int u,v;
            read(u,v);
            e[u].emplace_back(v);
            e[v].emplace_back(u);
        }
        int q;
        read(q);
        while(q--){
            read(m);
            if(f[m]!=m){
                continue;
            }
            vector<int> now=e[m];
            e[m].clear();
            for(auto it:now){
                int fa=find(it);
                if(fa==m){
                    continue;
                }
                pb(e[m],e[fa]);
                f[fa]=m;
            }
        }
        for(int i=0;i<n;i++){
            printf("%d%c",find(i),i==n-1?'\n':' ');
        }
    }
    return 0;
}

你可能感兴趣的:(多校,启发式合并)