bzoj1015

12 篇文章 0 订阅

这道题是要求一个动态的联通块数量。

刚开始的想法是强连通,找割点,然后发现打不下去。

所以想到了并查集。可是并查集如何删点?

我这里采用了逆时间建边,就是先把最后结果的边建好,再把删的点加回去,维护联通块数量。

#include<cstdio>
#include<cstdlib>
#include<cstring>
bool v[500000];//是否被释放
int p[500000]; 
struct mod{int x,y,next;};
mod q[500000];
int f[500000];
int first[500000],len=0;
int ans[500000];
void ins(int x,int y)
{
    len++;
    q[len].x=x;
    q[len].y=y;
    q[len].next=first[x];
    first[x]=len;
}
int find(int x)
{
 if (f[x]==x)return x;
 f[x]=find(f[x]);
 return f[x];   
}
int main()
{
 int n,m;
 scanf("%d%d",&n,&m);
 memset(first,-1,sizeof(first));
 for (int i=1;i<=m;i++)
 {
  int x,y;
  scanf("%d%d",&x,&y);
  ins(x,y);
  ins(y,x);
 }
 int k;
 scanf("%d",&k);
 memset(v,true,sizeof(v));
 int num=n;
 for (int i=1;i<=k;i++)
 {scanf("%d",&p[i]);v[p[i]]=false;}
 num-=k;
 //printf("#%d\n",num);
 for (int i=0;i<n;i++)f[i]=i;
 for (int x=0;x<n;x++)
 {
  if (v[x]==false)continue;
  for (int j=first[x];j!=-1;j=q[j].next)
  {
   int y=q[j].y;
   if (v[y]==false)continue;
   int fx=find(x),fy=find(y);
   if (fx==fy)continue;
    num--;
    f[fx]=fy;
  }
 }
 ans[k]=num;
 //printf("*%d\n",num);system("pause");
 for (int i=k;i>=1;i--)//倒着把点加入 
 {
  int x=p[i];
  v[x]=true;
  for (int j=first[x];j!=-1;j=q[j].next)
  {
   int y=q[j].y;
   if (v[y]==false)continue;
   int fx=find(x),fy=find(y);
   if (fx==x)
    f[fx]=fy;
   else
   {
    if (fx!=fy)
    {
     num--;
     f[fx]=fy;  
    }
   }
  }
  if (find(x)==x)num++;
  ans[i-1]=num;
 }
  for (int i=0;i<=k;i++)
  printf("%d\n",ans[i]);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值