P1197 [JSOI2008]星球大战——链式前向星+并查集

https://www.luogu.org/problem/P1197

这道题算是关闭农场的加强版吧,数据有点大,矩阵存不下;

也是记录删点操作,从后往前加边;

先将每个点都算成一个连通块,然后每连一条边连通块数就减一;

加一个点时不要忘记连通块数+1,然后合并;

还有数组要开大;

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=400010;
int pre[maxn*2],last[maxn],other[maxn*2],from[maxn*2],l;
int n,m,k;
int out_block[maxn*2],delete_order[maxn*2];
int num_block[maxn*2],tot_block;
int father[maxn*2];
void add(int x,int y)
{
    l++;
    from[l]=x;
    pre[l]=last[x];
    last[x]=l;
    other[l]=y;
}

int getfather(int x)
{
    if(father[x]==x) return x;
    father[x]=getfather(father[x]);
    return father[x];
}

void merge(int x,int y)
{
    int fx=getfather(x);
    int fy=getfather(y);
    father[fx]=fy;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    scanf("%d",&k);
    for(int i=1;i<=k;i++)
    {
        scanf("%d",&delete_order[i]);
        out_block[delete_order[i]]=1;
    }
    tot_block=n-k;
    for(int i=1;i<=n;i++) father[i]=i;
    for(int i=1;i<=m*2;i++)
    {
        if(!out_block[from[i]]&&!out_block[other[i]]&&getfather(from[i])!=getfather(other[i]))
        {
            merge(from[i],other[i]);
            tot_block--;
        }
    }
    num_block[k+1]=tot_block;
    for(int i=k;i>=1;i--)
    {
        out_block[delete_order[i]]=0;
        tot_block++;
        for(int p=last[delete_order[i]];p;p=pre[p])
        {
            int v=other[p];
            if(!out_block[v]&&getfather(delete_order[i])!=getfather(v))
            {
                tot_block--;
                merge(delete_order[i],v);
            }
        }
        num_block[i]=tot_block;
    }
    for(int i=1;i<=k+1;i++)
    {
        printf("%d
",num_block[i]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/WHFF521/p/11603164.html