1. 程式人生 > 其它 >luogu P7323 [WC2021] 括號路徑

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;
}