luogu P7323 [WC2021] 括號路徑
阿新 • • 發佈:2021-12-17
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; }