bzoj 1015 [JSOI2008]星球大战starwar

并查集

题目中是说将节点一个个摧毁,正着做并不好做

所以考虑在所有的星球摧毁后反着进行连边

在恢复一个节点后,则恢复了这个节点到之前已恢复的节点的连边,然后用并查集维护联通块即可

注意在同一个联通块中连边是不会改变联通块的个数的

所以只要处理联通块之间的边即可

#include <bits/stdc++.h>
using namespace std;
const int MAXN=4*1e5+100;
int n,m,k,fa[MAXN],q[MAXN],color[MAXN];
int now,nf[MAXN],vi[MAXN];
vector <int> e[MAXN],ans;
int find(int x)//并查集
{
    if (fa[x]==x)
      return fa[x];
    fa[x]=find(fa[x]);
    return fa[x];
}
void dfs(int x,int now)
{
    color[x]=now;
    for (int i=0;i<(int)e[x].size();i++)
    {
        if (color[e[x][i]])
          continue;
        dfs(e[x][i],now);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    scanf("%d",&k);
    for (int i=1;i<=k;i++)
    {
        scanf("%d",&q[i]);
        vi[q[i]]=1;
    }
    int co=0;
    for (int i=0;i<n;i++)
    {
        if (color[i])
          continue;
        co++;
        dfs(i,co);
    }//对残余的图进行染色,判断联通块
    printf("%d\n",co);
    for (int i=0;i<n;i++)
      fa[i]=i;
    for (int i=0;i<n;i++)
    {
        if (vi[i])
          continue;
        for (int j=0;j<(int)e[i].size();j++)
        {
            if (vi[e[i][j]])
              continue;
            if (find(e[i][j])!=find(i))
            {
                fa[find(i)]=find(e[i][j]);
            }
        }
    }
    for (int i=0;i<n;i++)
    {
        if (vi[i])
          continue;
        if (nf[find(i)]==0)
        {
            now++;
            nf[find(i)]=1;
        }
    }
    for (int i=k;i>=1;i--)
    {
        ans.push_back(now);
        int u;
        u=q[i];
        vi[u]=0;
        for (int j=0;j<(int)e[u].size();j++)
        {
            if (vi[e[u][j]])
              continue;
            int v;
            v=e[u][j];//进行加边
            if (find(u)!=find(v))
            {
                if (nf[find(u)]==1 && nf[find(v)]==1)
                {
                    nf[find(u)]=0;
                    now--;
                }
                fa[find(u)]=find(v);
            }
        }
        if (nf[find(u)]==0)
        {
            nf[find(u)]=1;
            now++;
        }
    }
    for (int i=(int)ans.size()-1;i>=0;i--)
      printf("%d\n",ans[i]);
}

 

posted @ 2019-07-16 11:57  SevenDawns  阅读(143)  评论(1编辑  收藏  举报
浏览器标题切换
浏览器标题切换end