對於兩條邊$(x_{1},y,c)$和$(x_{2},y,c)$,不難發現$x_{1}$與$x_{2}$徹底等價,所以能夠合併c++
重複此過程,合併以後用啓發式合併來合併邊集(注意自環也能夠參與合併,即$(x,y,c)$和$(y,y,c)$,那麼就將$x$和$y$合併),並用一個隊列來記錄操做ide
以後,當不存在此類邊,考慮一條合法路徑中必然有相鄰兩次,選擇了同類型的左右括號(先左後右),因爲不存在此類邊,不難證實這隻能在一條邊上往返,顯然無心義,即只能在合併後的集合內部選,並查集維護便可spa
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 300005 4 struct ji{ 5 int x,c,y; 6 }; 7 queue<ji>q; 8 map<int,int>mat[N]; 9 map<int,int>::iterator it; 10 int n,m,k,x,y,z,f[N],sz[N]; 11 long long ans; 12 int find(int k){ 13 if (k==f[k])return k; 14 return f[k]=find(f[k]); 15 } 16 void merge(int x,int y){ 17 x=find(x),y=find(y); 18 if (x==y)return; 19 if (mat[x].size()<mat[y].size())swap(x,y); 20 f[y]=x; 21 sz[x]+=sz[y]; 22 for(it=mat[y].begin();it!=mat[y].end();it++) 23 q.push(ji{x,(*it).first,(*it).second}); 24 } 25 int main(){ 26 scanf("%d%d%d",&n,&m,&k); 27 for(int i=1;i<=n;i++){ 28 f[i]=i; 29 sz[i]=1; 30 } 31 for(int i=1;i<=m;i++){ 32 scanf("%d%d%d",&x,&y,&z); 33 q.push(ji{y,z,x}); 34 } 35 while (!q.empty()){ 36 ji o=q.front(); 37 q.pop(); 38 o.x=find(o.x); 39 if (!mat[o.x][o.c])mat[o.x][o.c]=o.y; 40 else merge(mat[o.x][o.c],o.y); 41 } 42 for(int i=1;i<=n;i++) 43 if (f[i]==i)ans+=1LL*sz[i]*(sz[i]-1)/2; 44 printf("%lld",ans); 45 }