题目链接:见这里
题意: 给你一个图,然后有重边,每条边有一种颜色,然后每次查询两个点之间有多少种颜色是把这俩点直接相连的
解法:
这里要用到高维的并查集,定义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;
}