[LuoGu]P1197-并查集求连通块

题目链接:

tips:

  1.记录输入的哪些信息,是边读入,边处理还是都读入,后处理。

  2.倒着恢复,插入一个新点,用并查集判断是否连通。

//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<utility>
using namespace std;

const int maxN=400010;
const int maxM=200010;
vector<int> G[maxN];//邻接表
vector<pair<int,int> > e;//边集

int tmpK[maxN];
bool tag[maxN];
int ans[maxN];
int p[maxN];
int r[maxN];
int n,m;
int x,y;

void init(int x){
    for(int i=0;i<n;i++){
        p[i]=i;
        r[i]=0;
    }
}

int find(int x){
    if(p[x]==x) return x;
    else return p[x]=find(p[x]);
}

void unite(int x,int y){
    int fx=find(x);
    int fy=find(y);
    if(fx==fy) return;
    if(r[fx]< r[fy]){
        p[fx]=fy;
    }
    else{
        p[fy]=fx;
        if(r[fx] == r[fy]) r[fx]++;
    }
}

bool same(int x, int y){
    return find(x) == find(y);
}



int main(){
    cin>>n>>m;
    init(n);
    for(int i=0;i<m;i++){
        cin>>x>>y;
        G[x].push_back(y);
        G[y].push_back(x);
        e.push_back(make_pair(x,y));
    }
    int k;
    cin>>k;
    for(int i=0;i<k;i++){
        cin>>tmpK[i];
        tag[tmpK[i]]=1;
    }
    int s=e.size();
    for(int i=0;i<s;i++){
        int x=e[i].first;
        int y=e[i].second;
        if(!tag[x] && !tag[y]){
            unite(x,y);
        }
    }
    //统计全破坏后的连通块
    int cur_ans=0;
    for(int i=0;i<n;i++){
        if(!tag[i]&& find(i)==i){
            cur_ans++;
        }
    }
//倒着恢复被破坏的点,先假设刚恢复的点独自成块再判断恢复的点是否和其他块连通
    for(int i=k-1;i>=0;i--){
        ans[i]=cur_ans;
        int cur_K=tmpK[i];
        tag[cur_K]=0;
        cur_ans++;
        if(G[cur_K].size()){
            for(int j=0; j<G[cur_K].size(); j++){
                if(!tag[G[cur_K][j]]){
                    if(!same(cur_K,G[cur_K][j])){
                        cur_ans--;
                        unite(cur_K,G[cur_K][j]);
                    }
                }
            }
        }
    }
    cout<<cur_ans<<endl;
    for(int i=0;i<k;i++){
        cout<<ans[i]<<endl;
    }
    return 0;
}
View Code

ps:

日常不练习,就会手生。

理解会随着时间加深,看待的角度也会变化,比如刚开始时是用搜索(dfs)求连通块的,现在也可以从并查集这个角度看。

之前有在思考计算机建立的基础,数学基础、硬件基础;计算机语言的设计方面的东西(mit、南大)。

多思考本质、基础。比如之前思考的计算机语言的三大逻辑语句就可以编程处理问题了?

 

ref:https://blog.csdn.net/KIKO_caoyue/article/details/84073688

posted @ 2020-03-31 19:02  SUMay  阅读(173)  评论(0编辑  收藏  举报