传送门:hdu 4496
题意:给你n个点和m条边,依次连接这m条边。然后按照输入顺序删除每一条边,问你每次删掉一条边以后的图中的联通块个数。
思路:倒序加边,从一条边都不加到加入m-1条边(因为第一个输出的是删掉第一条边后的结果,所以不加入第一条边)。一条边都不加的时候联通块个数为n,即点的个数。每加入一条边判断这两个点是否拥有同一个父节点,如果不是说明他们在两个不同的联通块中,可以将他们合并,并且联通块个数是加入这条边之前的联通块个数-1;否则说明他们在同一个联通块中,加入这条边不改变联通块个数。
AC代码:
/********************************************** Author: StupidTurtle Date: 2018.5.20 Email: [email protected] **********************************************/ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll ; const int oo = 0x7f7f7f7f ; const int maxn = 1e4 + 7 ; const int maxm = 1e5 + 7 ; const int mod = 1e9 + 7 ; int pre[maxn] , ans[maxm] ; int Find ( int x ){ return x == pre[x] ? pre[x] : pre[x] = Find(pre[x]) ; } struct node{ int u , v ; }; node p[maxm] ; int main(void){ int n , m ; while ( ~scanf("%d%d",&n,&m ) ){ for ( int i = 0 ; i < n ; i ++ ){ pre[i] = i ; } for ( int i = 0 ; i < m ; i ++ ){ scanf("%d%d",&p[i].u,&p[i].v ); } ans[m] = n ; for ( int i = m - 1 ; i > 0 ; i -- ){ if ( ans[i+1] == 1 ){ ans[i] = 1 ; continue ; } int fu = Find(p[i].u) , fv = Find(p[i].v) ; if ( fu == fv ){ ans[i] = ans[i+1] ; } else { pre[fu] = fv ; ans[i] = ans[i+1] - 1 ; } } for ( int i = 1 ; i <= m ; i ++ ){ printf("%d\n",ans[i] ); } } return 0 ; }