想了半天决定第一篇就发一道水题的题解吧……这道题以前就看了但是神奇的第一次没有写对,然后今天写代码+调试,额……二十分钟……
题目懒得贴了,直接戳这里
题目大意就是给你一个图(毫无疑问稀疏图),然后每一次抹去其中一个节点,然后求这时的连通块个数。
第一次看这题的时候在学tarjan,第一反应就是每次把点去掉跑tarjan,然后看了下数据范围就放弃了【其实也能过几个点对不对233】
然后就想到用并查集,把所有的操作全部用一个数组存下来,然后倒着合并。
首先将所有要消除的点全部抹去,用并查集求出当前连通块的个数,然后根据给出的顺序,每一次“激活”一个点,然后和它所连的激活的点合并,最后倒着输出就可以了。
关于合并统计连通块个数:
①将所有要消除的点抹去后,ans:=n-k,然后在当前图中开始合并,即如果发现有两个点有边相连且不在同一个连通块中,那么合并两个连通块且ans:=ans-1。最后统计出的就是将所有指定的星球全部毁灭后的连通块个数。
②添加点时注意ans:=ans+1,因为当添加了一个点就相当于又添加了一个连通块.然后合并,统计方法和上面一样,如果不在一个连通块中则ans:=ans-1.此时统计出的是在当前所添加的星球未被毁灭之前的连通块个数
还有要注意的一点就是数据范围比较大,邻接矩阵不够存要用邻接表。另外为了时间更快用的并查集的路径压缩(不会直接度娘)
其他的就什么好说的了,我属于代码写的比较丑的类型也只写了八十多行,下面贴代码
1 program j01; 2 var x,y,n,m,i,j,k,t,ans:longint; 3 f:array[0..500000]of longint; 4 a,c:array[1..500000]of longint; 5 b:array[0..500000]of boolean; 6 q,next,head:array[0..500000]of longint; 7 function gg(i:longint):longint;//并查集查找部分,这里为了时间快用了压缩路径 8 var x:longint; 9 begin 10 if f[i]=i then exit(i); 11 x:=gg(f[i]); 12 f[i]:=x; 13 exit(x); 14 end; 15 procedure merge(i,j:longint); 16 var x,y:longint; 17 begin 18 x:=gg(i); 19 y:=gg(j); 20 f[x]:=y; 21 end; 22 procedure add(a,b:longint);//邻接表 23 begin 24 inc(t); 25 q[t]:=b; 26 next[t]:=head[a]; 27 head[a]:=t; 28 end; 29 begin 30 readln(n,m); 31 fillchar(head,sizeof(head),0); 32 t:=0; 33 for i:=1 to m do 34 begin 35 readln(x,y); 36 add(x,y); 37 add(y,x); 38 end; 39 readln(k); 40 fillchar(b,sizeof(b),true); 41 for i:=1 to k do 42 begin 43 readln(a[i]); 44 b[a[i]]:=false; 45 end; 46 ans:=n-k; 47 for i:=0 to n-1 do f[i]:=i; 48 for i:=0 to n-1 do 49 begin 50 j:=head[i]; 51 if b[i] then 52 while j<>0 do 53 begin 54 if b[q[j]] then 55 if gg(i)<>gg(q[j]) then 56 begin 57 dec(ans); 58 merge(i,q[j]); 59 end; 60 j:=next[j]; 61 end; 62 end;//统计最后连通块个数 63 for i:=k downto 1 do 64 begin 65 c[i]:=ans;//这里的ans记录的是i+1次毁灭星球之前连通块个数,即i次毁灭星球是后的连通块个数 66 b[a[i]]:=true; 67 ans:=ans+1; 68 j:=head[a[i]]; 69 while j<>0 do 70 begin 71 if b[q[j]] then 72 if gg(a[i])<>gg(q[j]) then 73 begin 74 dec(ans); 75 merge(a[i],q[j]); 76 end; 77 j:=next[j]; 78 end; 79 end;//统计每一次毁灭前连通块个数 80 writeln(ans); 81 for i:=1 to k do writeln(c[i]); 82 end.
时间: 2024-10-17 14:17:38