2020牛客暑期多校训练营(第三场)G题Operating on a Graph(并查集与链表)
2020牛客暑期多校训练营(第三场)G题Operating on a Graph(并查集与链表)
题意:给一个图,q次操作,输入一个颜色op,若无op颜色则不管,否则将op相邻的颜色改为op,输出最后每个点的颜色,最开始每个点的颜色等于本身的点。
题解:并查集比较简单,主要是不用链表或按秩合并操作会超时,因为枚举颜色最外层要一层,枚举外层每个点的颜色要一层,然后要在将那个颜色的最外层的点加入队列一层,共3层,在特例下会很慢(类似菊花连菊花,一个外层点很多的颜色,一下全部移到左边,一下全移到右边),用链表的话可以将第3层的时间变成O(1),优化很多时间。
代码部分:
#include<iostream>
#include<vector>
#include<list>
using namespace std;
int t,n,m,q,u,v,op,now,to;
vector<int>ho[800007];
list<int>lk[800007];
int fa[800007];
void init(){
for(int i=0;i<n;i++){
fa[i]=i;
ho[i].clear();
lk[i].clear();
lk[i].push_back(i);
}
}
int fin(int p){
if(p==fa[p])return p;
else{
return fa[p]=fin(fa[p]);
}
}
void solve(){
if(op!=fa[op]){
return;
}
int cnt=lk[op].size();
while(cnt--){
now=lk[op].front();
lk[op].pop_front();
for(int i=0;i<ho[now].size();i++){
to=fin(ho[now][i]);
if(to!=op){
fa[to]=op;
lk[op].splice(lk[op].end(),lk[to]);
}
}
}
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
ho[u].push_back(v);
ho[v].push_back(u);
}
scanf("%d",&q);
while(q--){
scanf("%d",&op);
solve();
}
for(int i=0;i<n;i++){
printf("%d ",fin(i));
}
puts("");
}
}