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