bzoj1015: [JSOI2008]星球大战starwar(并查集)
1015: [JSOI2008]星球大战starwar
题目:传送门
题解:
看完题之后很容易就会并查集的方向去想,然而正解就是这样的。
不过我们要稍微将思维转换一下:
初始化之后就进入枚举,可以直接将整个连通图加入答案,如果不是的话就在后面的判断里面减掉
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 int n,m; 8 struct node 9 { 10 int x,y,next; 11 }a[410000];int len,last[410000]; 12 void ins(int x,int y) 13 { 14 len++;a[len].x=x;a[len].y=y; 15 a[len].next=last[x];last[x]=len; 16 } 17 int fa[410000]; 18 int findfa(int x) 19 { 20 if(fa[x]!=x)fa[x]=findfa(fa[x]); 21 return fa[x]; 22 } 23 int b[410000],c[410000];bool bo[410000]; 24 int main() 25 { 26 scanf("%d%d",&n,&m); 27 len=0;memset(last,0,sizeof(last)); 28 for(int i=1;i<=m;i++) 29 { 30 int x,y; 31 scanf("%d%d",&x,&y); 32 ins(x,y);ins(y,x); 33 } 34 memset(bo,true,sizeof(bo)); 35 int k;scanf("%d",&k); 36 for(int i=1;i<=k;i++){scanf("%d",&b[i]);bo[b[i]]=false;} 37 for(int i=0;i<n;i++)fa[i]=i; 38 for(int i=1;i<=len;i+=2) 39 { 40 if(bo[a[i].x] && bo[a[i].y]) 41 { 42 int fx=findfa(a[i].x),fy=findfa(a[i].y); 43 if(fx!=fy)fa[fx]=fy; 44 } 45 } 46 int cnt=0; 47 for(int i=0;i<n;i++)if(fa[i]==i && bo[i])cnt++; 48 c[k+1]=cnt; 49 for(int i=k;i>=1;i--) 50 { 51 int x=b[i];bo[x]=true;cnt++; 52 for(int k=last[x];k;k=a[k].next) 53 { 54 int y=a[k].y; 55 if(bo[y]) 56 { 57 int fx=findfa(x),fy=findfa(y); 58 if(fx!=fy)fa[fx]=fy,cnt--; 59 } 60 } 61 c[i]=cnt; 62 } 63 for(int i=1;i<=k+1;i++)printf("%d\n",c[i]); 64 return 0; 65 }