合并不采用路径压缩,保证每次合并只修改一个节点的父亲,使当前版本与上一版本共用的节点尽可能的多
为防止并查集退化成链,采取按秩合并
\(code\):
void build(int L,int R,int &cur) { cur=++tree_cnt; if(L==R) { fa[cur]=L; return; } int mid=(L+R)>>1; build(L,mid,ls[cur]); build(mid+1,R,rs[cur]); } void merge(int L,int R,int pos,int fath,int pre,int &cur) { cur=++tree_cnt; if(L==R) { fa[cur]=fath; de[cur]=de[pre]; return; } ls[cur]=ls[pre],rs[cur]=rs[pre]; int mid=(L+R)>>1; if(pos<=mid) merge(L,mid,pos,fath,ls[pre],ls[cur]); if(pos>mid) merge(mid+1,R,pos,fath,rs[pre],rs[cur]); } int query(int L,int R,int pos,int cur) { if(L==R) return cur; int mid=(L+R)>>1; if(pos<=mid) return query(L,mid,pos,ls[cur]); if(pos>mid) return query(mid+1,R,pos,rs[cur]); } void add(int L,int R,int pos,int cur) { if(L==R) { de[cur]++; return; } int mid=(L+R)>>1; if(pos<=mid) add(L,mid,pos,ls[cur]); else add(mid+1,R,pos,rs[cur]); } int find(int pos,int cur) { int fath=query(1,n,pos,cur); if(pos==fa[fath]) return fath; return find(fa[fath],cur); } ...... read(a),read(b); root[i]=root[i-1]; int u=find(a,root[i]),v=find(b,root[i]); if(fa[u]==fa[v]) continue; if(de[u]>de[v]) swap(u,v); merge(1,n,fa[u],fa[v],root[i-1],root[i]); if(de[u]==de[v]) add(1,n,fa[v],root[i]);//合并 read(a); root[i]=root[a];//返回历史版本 read(a),read(b); root[i]=root[i-1]; int u=find(a,root[i]),v=find(b,root[i]); if(fa[u]==fa[v]) puts("1"); else puts("0");//查询
来源:https://www.cnblogs.com/lhm-/p/12229516.html