【并查集逆序】洛谷P1197

顺序做一定会超时
考虑逆序做
先把该删除的点全部删除
然后逆序加入图中,在加入的过程判断联通不联通;
不联通的话就让连通块的个数-1;然后把2个连通块连起来
还是比较难的

#include <bits/stdc++.h>
using namespace std;
const int N=4e5+5;

struct node{
    int f,t;
    int nex;
}edge[N];

int head[N];
int broken[N];
int tot=0;
int bb[N];
int root[N];

stack<int> res;
void add(int f,int t)
{
    ++tot;
    edge[tot].f=f;
    edge[tot].t=t;
    edge[tot].nex=head[f];
    head[f]=tot;
}

int fd(int a)
{
    if(root[a]==a){
        return a;
    }
    return root[a]=fd(root[a]);
}

void unit(int a,int b)
{
    int fa=fd(a);
    int fb=fd(b);
    if(fa!=fb){
        root[fa]=fb;
    }
}

int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++){
        head[i]=-1;
        root[i]=i;
    }

    int a,b;
    for(int i=1;i<=m;i++){
        cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    int k;
    cin>>k;
    for(int i=1;i<=k;i++){
        cin>>bb[i];
        broken[bb[i]]=1;
    }
    int total=n-k;
    for(int i=1;i<=tot;i++){
        if(!broken[edge[i].f]&&!broken[edge[i].t]){
            //cout<<"for"<<endl;
            if(fd(edge[i].f)!=fd(edge[i].t)){
                unit(edge[i].f,edge[i].t);
                total--;
            }
        }
    }
    res.push(total);
    for(int i=k;i>=1;i--){
        broken[bb[i]]=0;
        total++;
        for(int j=head[bb[i]];j!=-1;j=edge[j].nex){
            if(!broken[edge[j].t]){
                if(fd(bb[i])!=fd(edge[j].t)){
                   // cout<<bb[i]<<"---->"<<edge[j].t<<endl;
                    unit(bb[i],edge[j].t);
                    total--;
                }
            }
            //cout<<"===========  "<<bb[i]<<endl;
        }
        res.push(total);
        //cout<<total<<endl;
    }
    while(res.size()){
        int fr=res.top();
        cout<<fr<<endl;
        res.pop();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44833767/article/details/104581688
今日推荐