luogu 1197 星球大戰

去題面的傳送門
記得之前做過一個跟這個題很類似的。那道題是每次刪一條邊,問聯通塊的個數。正解就是離線處理,然後倒序加邊,用並查集維護。而這道題是刪點,同樣想到離線處理然後倒序加點,唯一的不同是這道題要把這個點連接的所有邊都for一遍。。。
話不多說,上代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn=200000+100;
int cnt,n,m,k;
int fist[maxn<<1],nxt[maxn<<1],num[maxn<<1],ans[maxn<<1],fa[maxn<<1];
bool vis[maxn<<1];
struct hh
{
    int f,t;
}e[maxn<<1];

void build(int f,int t)
{
    e[++cnt]=(hh){f,t};
    nxt[cnt]=fist[f];
    fist[f]=cnt;
}
int find(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
int main()
{
    memset(fist,-1,sizeof(fist)); 
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        build(x,y);
        build(y,x);
    }
    scanf("%d",&k);
    for(int i=1;i<=k;++i)
    {
        scanf("%d",&num[i]);
        vis[num[i]]=true;
    }
    for(int i=1;i<=n;++i) fa[i]=i;
    ans[k+1]=n-k;
    for(int i=1;i<=cnt;i+=2)
    {
        int u=e[i].f,v=e[i].t;
        int f1=find(u),f2=find(v);
        if(!vis[u]&&!vis[v]&&f1!=f2)
        {
            f1=fa[f2];
            ans[k+1]--;
        }
    }
    for(int i=k;i>=1;--i)
    {
        ans[i]=ans[i+1]+1;
        int u=num[i];
        vis[u]=false;
        for(int j=fist[u];j!=-1;j=nxt[j])
        {
            int v=e[j].t;
            if(vis[v]) continue;
            int f1=find(u),f2=find(v);
            if(f1!=f2)
            {
                ans[i]--;
                fa[f1]=f2;
            }
        }
    }   
    for(int i=1;i<=k+1;++i) printf("%d\n",ans[i]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章