P1197 [JSOI2008] 星球大战

P1197 [JSOI2008] 星球大战

题目简述

对于n个的点,他们之间有m条边,连接起来的点可以组成连通块,求每次破环一个点后剩余连通块个数


思路

还是不错的一道题,这题可以用并查集来做,正着做肯定行不通,所以我们倒着来建边,对于每次新加入的一个点,我们用链式前向星把他所连接的边都找出来,能加的都尽量加进去,再用并查集判断是不是在连通块里就可以出答案了qwq

BTW, 为什么数组开小了是会WA而不是RE啊qwq,害得我 debug 半天😧


代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
struct Edge{
  int _next,_to;
}e[N*2];
struct Node{
  int x,y;
}s[2*N];
int fa[2*N],vis[N*2],A[N*2];
int head[N*2],tot,kk[N*2];
int get_fa(int x){
  return (fa[x]==x)?x:(fa[x]=get_fa(fa[x]));
}
void add_edge(int u,int v){
  e[++tot]._next=head[u];
  e[tot]._to=v;
  head[u]=tot;
}
int main(){
  int n,m,k,ans;
  cin>>n>>m;
  for(int i=0;i<=n;i++)fa[i]=i;
  for(int i=1;i<=m;i++){
  	int x,y;
  	cin>>x>>y;
  	add_edge(x,y);
  	add_edge(y,x);
    s[i].x=x;s[i].y=y;
  }
  cin>>k;
  for(int i=1;i<=k;i++){
    int x;
    cin>>x;
    kk[i]=x;
    vis[x]=1;
  }
  int kdl=k+1;
  ans=n-k;
  for(int i=1;i<=m*2;i++){
    if(vis[s[i].x]==0&&vis[s[i].y]==0){
      int fx=get_fa(s[i].x),fy=get_fa(s[i].y);
      if(fx==fy)continue;
      fa[fx]=fy;
      ans--;
    }
  }
  A[kdl--]=ans;
  for(int i=k;i>=1;i--){
    ans++;
    vis[kk[i]]=0;
    for(int j=head[kk[i]];j;j=e[j]._next){
      int v=e[j]._to;
      if(vis[kk[i]]==0&&vis[v]==0){
        int fx=get_fa(kk[i]),fy=get_fa(v);
        if(fx==fy)continue;
        fa[fx]=fy;ans--;
      }
    }
    A[kdl--]=ans;
  }
  for(int i=1;i<=k+1;i++)cout<<A[i]<<endl;
  return 0;
}

posted @   paper_plane  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示