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
",c[i]);
64     return 0;
65 }
原文地址:https://www.cnblogs.com/CHerish_OI/p/8485306.html