考场想明白的都是神仙,受我一膜!看了题解到现在我都只是模模糊糊想清楚了。
考场上我的想法是从一个点不停地走反向边扩展,就能找到所有的这种情况:(A_1 ightarrow A_2 ightarrow A_n ightarrow B leftarrow C_n leftarrow C_2 leftarrow C_1)
然后再写一个( ext{floyd}),这样复杂度大概是阶乘?不管了,拿了( ext{32pts})跑路了。
正解的想法是每个点我们只拓展一条边,即找到所有的(A ightarrow B leftarrow C),大大减小了复杂度。
这样是不是计算不到(D ightarrow A ightarrow B leftarrow C leftarrow E)呢?是的。所以考虑一个小操作。
考虑将(A)和(C)合并,那么就可以这样(D ightarrow AC leftarrow E)计算到了。
考虑并查集按秩合并,复杂度(Theta(nlog n))或(Theta(n log^2 n)),就看你愿不愿意写哈希表了。
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=3e5+10;
const int mod=1e9+7;
int n,m,k;
map<int,int>mp[maxn];
map<int,int>::iterator it;
queue<pair<int,int> >q;
#define fi first
#define se second
int fa[maxn],siz[maxn];
long long ans;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
inline int find(int x){
if(fa[x]==x)return x;
return find(fa[x]);
}
inline void merge(int x,int y){
int s=find(x),t=find(y);
if(s==t)return;
if(siz[s]<siz[t])swap(s,t);
fa[t]=s;siz[s]+=siz[t];
for(it=mp[t].begin();it!=mp[t].end();it++){
if(mp[s][it->fi])q.push(make_pair(it->se,mp[s][it->fi]));
else mp[s][it->fi]=it->se;
}
}
int main(){
n=read(),m=read(),k=read();
int x,y,z;
for(int i=1;i<=m;i++){
x=read(),y=read(),z=read();
if(mp[y][z])q.push(make_pair(x,mp[y][z]));
else mp[y][z]=x;
}
for(int i=1;i<=n;i++)
fa[i]=i,siz[i]=1;
while(!q.empty()){
x=q.front().fi;
y=q.front().se;
q.pop();
merge(x,y);
}
for(int i=1;i<=n;i++)
if(fa[i]==i)ans+=1ll*siz[i]*(siz[i]-1)/2;
printf("%lld
",ans);
return 0;
}