题目
CF506D Mr. Kitayuta's Colorful Graph
给出一个无向图,每条边有颜色,每次询问两点间可以由多少种不同颜色的路径相互到达(要求路径上全是那一种颜色)。
分析
直接开一个 ( ext{unorderedmap}) ,维护每一个点对应颜色的并查集父亲。
然后考虑记忆化答案,每次直接询问就是直接查找和这个点有连边的所有颜色,查看其是否和另外一个点在这个颜色上连通。
时间复杂度是 (O(nalpha(n)sqrt{n})) 的。
分析:
如果一个点连出去的颜色超过了 (sqrt{n}) 种,那么这样的点不超过 (sqrt{n}) 个,因为我们记忆化过,所以这样的总状态只有 (nsqrt{n}) 。
剩下的是没有超过 $ sqrt{n}$ 的,直接暴力询问即可。
时间复杂度 (O(nalpha(n)sqrt{n}))
注意!( ext{unorderedmap}) 的下标访问非常慢!要使用 (count) 函数!
代码
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void read(T &x){
x=0;bool f=false;char ch=getchar();
while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
x=f?-x:x;
return ;
}
template<typename T>
inline void write(T x){
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10^48);
return ;
}
#define PII pair<int,int>
#define fi first
const int N=1e5+5,M=2e5+5,MOD=1e9+7;
unordered_map<int,int>fa[N],Ans[N];
int n,m,q;
int Getfa(int x,int col){return fa[x][col]==x?x:(fa[x][col]=Getfa(fa[x][col],col));}
inline void Merge(int x,int y,int col){
if(!fa[x].count(col)) fa[x][col]=x;
if(!fa[y].count(col)) fa[y][col]=y;
x=Getfa(x,col),y=Getfa(y,col);
if(x==y) return ;
fa[x][col]=y;
return;
}
signed main(){
read(n),read(m);
for(register int i=1,u,v,w;i<=m;i++) read(u),read(v),read(w),Merge(u,v,w);
read(q);
while(q--){
int u,v,res=0;read(u),read(v);
if(fa[u].size()>fa[v].size()) swap(u,v);
if(Ans[u].count(v)){write(Ans[u][v]);putchar('
');continue;}
for(PII t:fa[u]) res+=(fa[v].count(t.fi)&&Getfa(u,t.fi)==Getfa(v,t.fi));
write(Ans[u][v]=res);putchar('
');
}
return 0;
}
扩展
貌似有 (bitset) 高妙做法:一念之间、、 的博客