HYSBZ 1015/BZOJ1015 星球大战starwar
Description
很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系。某一天,凭着一个偶然的
机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球。这些星球通过特殊的以太隧道互相直
接或间接地连接。 但好景不长,很快帝国又重新造出了他的超级武器。凭借这超级武器的力量,帝国开始有计划
地摧毁反抗军占领的星球。由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来。现在,反抗军首
领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度求出每
一次打击之后反抗军占据的星球的连通快的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则
这两个星球在同一个连通块中)。
Input
输入文件第一行包含两个整数,N (1 < = N < = 2M) 和M (1 < = M < = 200,000),分别表示星球的
数目和以太隧道的数目。星球用 0 ~ N-1的整数编号。接下来的M行,每行包括两个整数X, Y,其中(0 < = X <>
Y 表示星球x和星球y之间有“以太”隧道,可以直接通讯。接下来的一行为一个整数k,表示将遭受攻击的星球的
数目。接下来的k行,每行有一个整数,按照顺序列出了帝国军的攻击目标。这k个数互不相同,且都在0到n-1的范
围内。
Output
第一行是开始时星球的连通块个数。接下来的K行,每行一个整数,表示经过该次打击后现存星球
的连通块个数
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
题解:
显然一看就知道是并查集,但是需要不断删除点,然而并查集并不支持删除操作。而且路径压缩过后,每个点显然只与根节点有关系而找不到子节点与其他子节点的关系了,所以只能反过来做,先求出所有星球被炸完后的连通分量,再把被炸的星球一个一个加上去,维护连通分量个数即可。
另外最后输出答案的时候用cout就runtime error??害得我查了一小时的bug...我真他娘服了
1 #include <iostream> 2 #include <string.h> 3 #include <cstdio> 4 #include <algorithm> 5 #include <queue> 6 #pragma warning ( disable : 4996 ) 7 8 #define sigma_size 26 9 10 using namespace std; 11 12 const int inf = 0x3f3f3f3f; 13 const int vspot = 4e5 + 5; 14 const int espot = 2e5 + 5; 15 16 struct node { 17 int to; 18 int next; 19 }e[vspot]; 20 21 int N, M; 22 int cnt, linjie[vspot], pre[vspot], num; 23 int hit[vspot]; //hit[x]表示x号星球是否毁灭 24 int fin[vspot]; //fin记录被毁灭星球的顺序号数 25 int ans; 26 27 int find( int x ) { return x==pre[x]?x:pre[x]=find(pre[x]); } 28 29 void add( int x, int y ) 30 { 31 e[cnt].to = y; e[cnt].next = linjie[x]; linjie[x] = cnt++; 32 e[cnt].to = x; e[cnt].next = linjie[y]; linjie[y] = cnt++; 33 } 34 35 void init() 36 { 37 cnt = num = 0; 38 ans = N; 39 memset( linjie, -1, sizeof(linjie) ); 40 for( int i = 0; i <= N; i++ ) 41 pre[i] = i; 42 } 43 44 void read() 45 { 46 int x, y; 47 for ( int i = 0; i < M; i++ ) 48 { 49 scanf( "%d %d", &x, &y ); 50 add( x, y ); 51 } 52 53 cin >> num; 54 for ( int i = 1; i <= num; i++ ) 55 { 56 scanf("%d", &x); 57 fin[i] = x; 58 hit[x] = 1; 59 } 60 } 61 62 void merge(int x) 63 { 64 int xr = find(x); 65 for ( int y = linjie[x]; y+1; y = e[y].next ) 66 if ( !hit[e[y].to] ) 67 { 68 int yr = find(e[y].to); 69 if ( yr != xr ) 70 { 71 pre[yr] = xr; 72 ans--; 73 } 74 } 75 } 76 77 int main() 78 { 79 cin >> N >> M; 80 init(); 81 read(); 82 //先 画出图 83 for( int i = 0; i < N; i++ ) 84 { 85 if ( !hit[i] ) 86 merge(i); 87 else 88 ans--; //一个星球被毁灭时,它本身就不算一个连通分量 89 } 90 fin[num+1] = ans; //最后一个星球被毁灭后剩下的连通分量个数 91 //一个一个加点和加边 92 for ( int i = num; i > 0; i-- ) 93 { 94 hit[fin[i]] = 0; 95 ans++; //将一个星球加回来时,相当于多了一个连通分量 96 97 merge(fin[i]); 98 fin[i] = ans; 99 } 100 ////////////////用cout就会runtime error///////////////////////// 101 for( int i = 1; i <= num+1; i++ ) 102 printf("%d\n",fin[i]); 103 104 return 0; 105 }