To_Heart—题解——老旧的桥

1.png

思路

首先,我们读题可发现要开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]);
	}
}
posted @ 2020-08-11 21:26  To_Heart  阅读(49)  评论(0编辑  收藏  举报