2600 城镇规划 (并查集 set)
小A最近在玩《都市:天际线》这款游戏,他在不断地建设着自己的城市(比如说修路盖房这种)。
但是一个没有贸易的城市是没有灵魂的,所以小A的城市中有许许多多的贸易来往,给这个城市带来源源不断的资金。
然而小A为了展现自己高超的游戏技巧,给自己打了一个增加游戏难度的mod,使得贸易的难度陡然上升。
在这个mod中,城市中的每一条路都有一个颜色C,假设贸易经过的路径序列为Ci(i=1,2,…,n),那么需要满足C_(2*k-1)=C_(2*k) (2*k<=n)的路径才能够成功完成这个贸易,否则就会出现诸如强盗打劫货物,货车翻车等事件导致贸易失败。
但是小A其实并没有100%计算正确的信心,所以他希望你能一直帮忙告诉他,他下一次准备进行的从A点到B点的贸易是否能够成功,由于小A的城市在不断施工,所以随时可能有一条路被建成。
#include<bits/stdc++.h>
using namespace std;
const int M=100005;
int n,m,Q,tot,fa[M],head[M],Next[M*4],vet[M*4],w[M*4];
set<int> s[M]; //s[i]表示i走一步可到达的点集
set<int>::iterator it;
int find(int x){
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
void hb(int x,int y){ //合并x和y所在集合,包括set的合并
int p=find(x), q=find(y);
if(p==q) return;
if(s[p].size()<s[q].size()) swap(p,q);
fa[q]=p; //让小集合q合并到大集合p中
for(it=s[q].begin(); it!=s[q].end(); it++) s[p].insert(*it);
s[q].clear();
}
void unionset(int x,int y,int z){
//x和y的边表中颜色也为z的点合并
for(int i=head[y]; i; i=Next[i]){
if(w[i]==z) hb(x,vet[i]);
}
}
void add(int x,int y,int z){
Next[++tot]=head[x], vet[tot]=y, w[tot]=z;
head[x]=tot;
}
void work(int x,int y,int z){
int p=find(x), q=find(y);
s[p].insert(y), s[q].insert(x); //走一步可达
unionset(x,y,z); unionset(y,x,z);
add(x,y,z); add(y,x,z);
}
int main(){
scanf("%d%d%d",&n,&m,&Q);
for(int i=1; i<=n; i++) fa[i]=i;
for(int i=1; i<=m; i++){
int x,y,z; scanf("%d%d%d",&x,&y,&z);
work(x,y,z);
}
for(int i=1; i<=Q; i++){
char op[3]; scanf("%s",op);
int x,y,z;
if(op[0]=='?'){
scanf("%d%d",&x,&y);
int p=find(x), q=find(y);
//printf("x=%d y=%d p=%d q=%d\n",x,y,p,q);
if(p==q || s[p].find(y)!=s[p].end()) printf("Yes\n");
else printf("No\n");
}else{
scanf("%d%d%d",&x,&y,&z);
work(x,y,z);
}
}return 0;
}