506D. Mr. Kitayuta's Colorful Graph(并查集+各种卡时空复杂度的技巧)

Kitayuta先生刚刚购买了一个具有n个顶点和m个边的无向图。图的顶点编号为1到n。每个边(即边i)的颜色为ci,连接顶点ai和bi。

Kitayuta先生希望您处理以下q个查询。

在第i个查询中,他给您两个整数ui和vi。

查找满足以下条件的颜色数:该颜色的边缘直接或间接连接顶点ui和顶点vi。

题解:

对每种颜色用并查集维护连通性,然后对每个询问,枚举其中一个点涉及的所有颜色,统计答案。

并查集用Map开,对询问去重,枚举涉及颜色较少的那个点,同时Map用unordered_map,把这题卡掉了,这四点缺一个就过不去。证明我是真的不会证,晕了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
unordered_map<int,int> f[maxn];
map<pair<int,int>,int> ans;
vector<int> g[maxn];
vector<int> v1,v2;
int n,m,q;
int x[maxn],y[maxn];
int findfather (int x,int c) {
    int a=x;
    while (f[x][c]) x=f[x][c];
    while (f[a][c]) {
        int z=a;
        a=f[a][c];
        f[z][c]=x;
    }
    return x;
}
void Union (int x,int y,int c) {
    x=findfather(x,c);
    y=findfather(y,c);
    if (x!=y)  {
        f[x][c]=y;
    }
}
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(x,y,c);
    }
    scanf("%d",&q);
    for (int i=1;i<=q;i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        if (ans[make_pair(x,y)]) {
            printf("%d\n",ans[make_pair(x,y)]-1);
            continue;
        }
        int sum=0;
        if (f[x].size()>f[y].size()) swap(x,y);
        for (auto it=f[x].begin();it!=f[x].end();it++) {
            int c=it->first;
            if (f[y].count(c)&&findfather(x,c)==findfather(y,c)) sum++;
        }
        printf("%d\n",sum);
        ans[make_pair(x,y)]=sum+1;
        ans[make_pair(y,x)]=sum+1;
    }
} 

 

posted @ 2021-02-01 23:15  zlc0405  阅读(150)  评论(0编辑  收藏  举报