[loj3462]括號路徑

對於兩條邊$(x_{1},y,c)$和$(x_{2},y,c)$,不難發現$x_{1}$與$x_{2}$徹底等價,所以能夠合併c++

重複此過程,合併以後用啓發式合併來合併邊集(注意自環也能夠參與合併,即$(x,y,c)$和$(y,y,c)$,那麼就將$x$和$y$合併),並用一個隊列來記錄操做ide

以後,當不存在此類邊,考慮一條合法路徑中必然有相鄰兩次,選擇了同類型的左右括號(先左後右),因爲不存在此類邊,不難證實這隻能在一條邊上往返,顯然無心義,即只能在合併後的集合內部選,並查集維護便可spa

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=
 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 }
View Code
相關文章
相關標籤/搜索