To_Heart—题解——老旧的桥
思路
首先,我们读题可发现要开long long!!!
咳咳,进入正题:
因为输入保证开始时每一座小岛都是相连的,那么我们可以倒序处理,把塌桥的过程转换为建桥的过程,用sum数组存放当前不可以连接的岛屿,那么sum[m+1]就是所有点都不可以相连的情况(因为此时所有的边都掉完了);
我们可以在进入循环的时候通过并查集确认每座岛的连接情况;
进入处理后,我们可以找这座桥的两个小岛的根节点是否相同,如果相同,就说明即使这条边掉了边上的两点也可以相连,和最终结果没关系所以sum[i]=sum[i+1];
如果不相同,那么说明这条边是两点联通的必要桥,设这两点为a,b那么此时我们就需要把a的根节点设为b(反过来也可),并且此时sum的值也会改变,因为此时从a的根节点到b的根节点就可以联通了,所以sum就需要减掉他们的积。
代码如下:
#include <bits/stdc++.h>
using namespace std;
long long pre[300005];
long long a[300005],b[300005];
long long sum[300005],tot[300005];
long long Find(long long x) { //找根节点
if(pre[x]!=x)
pre[x]=Find(pre[x]);
return pre[x];
}
void Join(long long x, long long y) { //加入
long long fx = Find(x), fy = Find(y);
pre[fx] = fy;
}
int main() {
long long n, m;
scanf("%lld%lld",&n,&m);
for (int i=1;i<=n;i++){ //初始化
pre[i]=i;
sum[i]=1;
}
for(int i=1;i<=m;i++){
scanf("%lld%lld",&a[i],&b[i]);
}
tot[m+1]=n*(n-1)/2;
for(int i=m;i>=1;i--){
long long fx=Find(a[i]),fy=Find(b[i]);
if(fx!=fy){
Join(fx,fy);
long long x=sum[fx]*sum[fy];
tot[i]=tot[i+1]-x;
sum[Find(a[i])]=sum[fx]+sum[fy];
}
else
tot[i]=tot[i+1];
}
for(int i=2;i<=m+1;i++){
printf("%lld\n",tot[i]);
}
}