Codeforces Round #286 (Div. 1) D. Mr. Kitayuta's Colorful Graph 高维并查集,STL连招

来源:互联网 发布:星光网络摄像机 编辑:程序博客网 时间:2024/06/10 07:29

题目链接:见这里
题意: 给你一个图,然后有重边,每条边有一种颜色,然后每次查询两个点之间有多少种颜色是把这俩点直接相连的
解法:
这里要用到高维的并查集,定义fa[u][c]=v表示节点u的颜色c属于集合v,由于无法开出这么大的二维数组,且实际边的数量很少,可以考虑使用map。

每次加边的时候,如果该节点u的颜色c不属于任何集合,则将u作为当前集合的根。每次加入一条边,相当于合并两个不同的集合。

询问的时候可以暴力查找,同时记录哪些被查找过,下次不再重复查找。枚举u的每一种颜色集合,验证v的这个颜色是否与u属于同一集合,即u,v能否由同一颜色的路径连通。

这题有个坑点,就是普通的map会超时,要使用unordered_map。
代码:

//CF 506D DSU#include <bits/stdc++.h>using namespace std;const int maxn = 100007;int n, m, q;unordered_map <int, int> fa[maxn], ans[maxn];int find_set(int v, int c){    if(fa[v][c] == v) return v;    return fa[v][c] = find_set(fa[v][c], c);}void union_set(int x, int y, int c){    if(fa[x].find(c) == fa[x].end()) fa[x][c] = x;    if(fa[y].find(c) == fa[y].end()) fa[y][c] = y;    int fx = find_set(x, c), fy = find_set(y, c);    if(fx != fy) fa[fx][c] = fy;}int main(){    scanf("%d%d", &n, &m);    for(int i = 1; i <= m; i++){        int x, y, c;        scanf("%d%d%d", &x, &y, &c);        union_set(x, y, c);    }    scanf("%d", &q);    while(q--){        int x, y, Ans = 0;        scanf("%d%d", &x, &y);        if(ans[x].find(y) != ans[x].end()){            printf("%d\n", ans[x][y]); continue;        }        int s1 = fa[x].size(), s2 = fa[y].size();        if(s1 > s2) swap(x, y);        for(auto u : fa[x]){            if(fa[y].find(u.first) != fa[y].end() && find_set(x, u.first) == find_set(y, u.first)) Ans++;        }        ans[x][y] = ans[y][x] = Ans;        printf("%d\n", Ans);    }    return 0;}
0 0