題目描述
有N個島嶼和M座橋樑,第i座橋樑雙向連接編號爲Ai和Bi的兩座島嶼。
最初,我們可以使用這些橋樑在任何兩個島嶼之間旅行。
然而,調查結果顯示,從第1座到第M座橋樑都會因老化而依次倒塌。每倒塌一座橋樑,就會存在多對島嶼(a,b)(其中a<b),使得我們不能再利用剩下的一些橋樑在a島和b島之間旅行了。
假設倒塌順序是:從第1座到第M座橋樑依次倒塌,那麼請你分別計算在橋樑i(1≤i≤M)倒塌後有多少對島嶼(a,b)之間不能再進行通行了。
請注意,答案可能超過32位整數類型。
輸入輸出格式
輸入格式:
第一行是兩個整數N和M,分別是島嶼的數量和橋樑的數量。
接下來有M行,每行兩個整數Ai和Bi ,表示連接島嶼Ai和Bi的一座橋樑。
輸出格式:
輸出M行,每行一個整數,依次表示當第i座橋倒塌後不能再進行通行的島嶼對數。
輸入輸出樣例
輸入樣例#1:
4 5
1 2
3 4
1 3
2 3
1 4
輸出樣例#1:
0
0
4
5
6
輸入樣例#2:
6 5
2 3
1 2
5 6
3 4
4 5
輸出樣例#2:
8
9
12
14
15
輸入樣例#3:
2 1
1 2
輸出樣例#3:
1
說明
【樣例1說明】
例如,當第1到第3座橋樑倒塌時,答案爲4,因爲我們不能再在橋樑對(1,2)、(1,3)、(2,4)和(3,4)之間通行。
【數據範圍】
對於100%的數據:2≤N≤105;1≤M≤105;1≤Ai<Bi≤N
所有的(Ai,Bi)都是不同的。
#include<bits/stdc++.h>
using namespace std;
long long n,m,cnt;
const int Max=2000010;
long long fa[Max];
long long first[Max],next[Max],from[Max],to[Max],tot[Max],ans[Max];//tot爲以i爲fa的聯通塊中點個數
long long broke[Max];
void init()
{
for(int i=1;i<=n;i++){
fa[i]=i;
tot[i]=1;
}
}
int findfa(long long x) {return fa[x]==x?x:fa[x]=findfa(fa[x]);}
void mergefa(long long a,long long b)
{
long long t1=findfa(a),t2=findfa(b);
if(t1!=t2) fa[t2]=t1;
}
void build(long long u,long long v)
{
next[++cnt]=first[u];
first[u]=cnt;
to[cnt]=v;
from[cnt]=u;
}
int main()
{
cin>>n>>m;
init();
for(int i=1;i<=m;i++){
long long a,b; cin>>a>>b;
build(a,b);
}
ans[m+1]=n*(n-1)/2;
for(int i=m;i>=1;i--)
{
// for(int j=1;j<=n;j++)
// cout<<fa[j]<<' ';
// cout<<endl;
long long a=findfa(from[i]),b=findfa(to[i]);
if(a!=b){
mergefa(from[i],to[i]);
ans[i]=ans[i+1]-(long long)(tot[a]*tot[b]);
tot[findfa(from[i])]=tot[a]+tot[b];
}
else
ans[i]=ans[i+1];
}
for(int i=2;i<=m+1;i++)
cout<<ans[i]<<endl;
return 0;
}