luogu P7323 [WC2021] 括号路径
https://www.luogu.com.cn/problem/P7323
考场上降大智了
首先发现如果\(x->y,y->z\)合法,那么\(x->z\)也一定合法
那么对于这样的同种颜色的两条边\(y->x,z->x\),那么\(z->y\)一定合法
就可以把\(z,y\)合并
一路合并下去,再看看每个集合里有多少个,简单计算即可
code:
#include<bits/stdc++.h>
#define N 300050
#define ll long long
using namespace std;
map<int, int> mp[N];
queue<pair<int, int> > q;
int fa[N];
int get(int x) {
return fa[x] == x? x : (fa[x] = get(fa[x]));
}
void merge(int x, int y) {
x = get(x), y = get(y);
if(x == y) return;
if(mp[x].size() > mp[y].size()) swap(x, y);
for(auto it : mp[x]) {
if(mp[y][it.first]) q.push(make_pair(mp[y][it.first], it.second));
else mp[y][it.first] = it.second;
}
fa[x] = y; mp[x].clear();
}
void solve() {
while(q.size()) {
int x = q.front().first, y = q.front().second; q.pop();
//printf("%d %d\n", x, y);
merge(x, y);
}
}
int n, m, k, gs[N];
int main() {
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; i ++) fa[i] = i;
for(int i = 1; i <= m; i ++) {
int u, v, c;
scanf("%d%d%d", &u, &v, &c), swap(u, v);
if(!mp[u][c]) mp[u][c] = v;
else q.push(make_pair(mp[u][c], v));
}
solve();
for(int i = 1; i <= n; i ++) gs[get(i)] ++;
ll ans = 0;
for(int i = 1; i <= n; i ++) if(get(i) == i) {
ans += 1ll * gs[i] * (gs[i] - 1) / 2;
}
printf("%lld", ans);
return 0;
}