【BZOJ】【1015】 【JSOI2008】星球大战starwar

并查集/时光倒流


  删点维护连通块个数比较难处理,所以我们就逆序来做,先处理最后状态下有多少连通块,再依次加入被删的点,这样就变删点为加点,利用并查集即可维护连通块个数。

 1 /**************************************************************
 2     Problem: 1015
 3     User: Tunix
 4     Language: C++
 5     Result: Accepted
 6     Time:1208 ms
 7     Memory:11488 kb
 8 ****************************************************************/
 9  
10 //BZOJ 1015
11 #include<vector>
12 #include<cstdio>
13 #include<cstring>
14 #include<cstdlib>
15 #include<iostream>
16 #include<algorithm>
17 #define rep(i,n) for(int i=0;i<n;++i)
18 #define F(i,j,n) for(int i=j;i<=n;++i)
19 #define D(i,j,n) for(int i=j;i>=n;--i)
20 #define pb push_back
21 using namespace std;
22 inline int getint(){
23     int v=0,sign=1; char ch=getchar();
24     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
25     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
26     return v*sign;
27 }
28 const int N=4e5+10,M=4e5+10,INF=~0u>>2;
29 typedef long long LL;
30 /******************tamplate*********************/
31 int n,m;
32 int to[M],next[M],head[N],cnt;
33 void ins(int x,int y){to[++cnt]=y;next[cnt]=head[x];head[x]=cnt;}
34 void add(int x,int y){ins(x,y);ins(y,x);}
35 int fa[N],ans[N],des[N];
36 int Find(int x){return x==fa[x] ? x : fa[x]=Find(fa[x]);}
37 bool sign[N],vis[N];
38 void dfs(int x){
39     vis[x]=1;
40     for(int i=head[x];i;i=next[i])
41         if (!vis[to[i]] && !sign[to[i]]){
42             fa[to[i]]=fa[x];
43             dfs(to[i]);
44         }
45 }
46  
47 int main(){
48 #ifndef ONLINE_JUDGE
49     freopen("1015.in","r",stdin);
50     freopen("1015.out","w",stdout);
51 #endif
52     n=getint(); m=getint();
53     int x,y;
54     F(i,1,m){
55         x=getint(); y=getint();
56         add(x,y);
57     }
58     int q=getint();
59     F(i,1,q){
60         des[i]=getint(); sign[des[i]]=1;
61     }
62     rep(i,n) fa[i]=i;
63     int cnt=0;
64     rep(i,n) if (!sign[i] && !vis[i]){
65         dfs(i);
66         cnt++;
67     }
68     ans[q]=cnt;
69     D(i,q,1){
70         x=des[i];cnt++;sign[x]=0;
71         for(int j=head[x];j;j=next[j])
72             if (!sign[to[j]]){
73                 int f1=Find(to[j]),f2=Find(x);
74                 if (f1!=f2) {fa[f1]=f2;cnt--;}
75             }
76         ans[i-1]=cnt;
77     }
78     F(i,0,q) printf("%d\n",ans[i]);
79     return 0;
80 }
View Code

1015: [JSOI2008]星球大战starwar

Time Limit: 3 Sec  Memory Limit: 162 MB
Submit: 3230  Solved: 1435
[Submit][Status][Discuss]

Description

很 久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系。某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系 中几乎所有的星球。这些星球通过特殊的以太隧道互相直接或间接地连接。 但好景不长,很快帝国又重新造出了他的超级武器。凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球。由于星球的不断被摧毁,两个星球之间的通 讯通道也开始不可靠起来。现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度求出每一次打 击之后反抗军占据的星球的连通快的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则这两个星球在同一个连通块中)。

Input

输 入文件第一行包含两个整数,N (1 <= N <= 2M) 和M (1 <= M <= 200,000),分别表示星球的数目和以太隧道的数目。星球用0~N-1的整数编号。接下来的M行,每行包括两个整数X, Y,其中(0<=X<>Y

Output

输出文件的第一行是开始时星球的连通块个数。接下来的N行,每行一个整数,表示经过该次打击后现存星球的连通块个数。

Sample Input

8 13
0 1
1 6
6 5
5 0
0 6
1 2
2 3
3 4
4 5
7 1
7 2
7 6
3 6
5
1
6
3
5
7

Sample Output

1
1
1
2
3
3

HINT

Source

[Submit][Status][Discuss]
posted @ 2015-04-10 08:51  Tunix  阅读(...)  评论(...编辑  收藏