「BZOJ1015」[JSOI2008] 星球大战starwar
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
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
1
1
2
3
3
题解
给定一张图,支持删点和询问连通块个数
按操作顺序处理的话要在删除点的同时维护图的形态(即图具体的连边情况),这是几乎不可做的
我们发现,这道题可以先读入操作,把没删的点的边先连上,然后再倒序处理操作
这样的话从删点变成了加点,而且只要维护连通块的数量,用并查集可以快速的解决这个问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int tot,n,m,d,father[400001],head[400001],q[400001],ans[400001],cnt=1; bool used[400001],des[400001]; struct data{int to,next;}e[400001]; int find(int x){return x==father[x]?x:father[x]=find(father[x]);} void ins(int u,int v) { cnt++;e[cnt].to=v;e[cnt].next=head[u];head[u]=cnt; cnt++;e[cnt].to=u;e[cnt].next=head[v];head[v]=cnt; } void add(int x) { int i=head[x],p=find(x),q; while(i) { if(used[e[i].to]) { q=find(e[i].to); if(p!=q){father[q]=p;tot--;} } i=e[i].next; } } int main() { scanf("%d%d",&n,&m); for(int i=0;i<n;i++)father[i]=i; for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); ins(x,y); } scanf("%d",&d); for(int i=1;i<=d;i++) { scanf("%d",&q[i]); des[q[i]]=1; } for(int i=0;i<n;i++) { if(!des[i]) { tot++; add(i); used[i]=1; } } ans[d+1]=tot; for(int i=d;i>0;i--) { tot++; add(q[i]); used[q[i]]=1; ans[i]=tot; } for(int i=1;i<=d+1;i++)printf("%d\n",ans[i]); return 0; } |
黄学长这题题解可以再详细一点么(逃
详细了一点QAQ。。。酱紫?
谢谢