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;
}
posted @ 2021-12-17 08:37  lahlah  阅读(32)  评论(0编辑  收藏  举报