Almost Union-Find UVA 11987

来源:互联网 发布:iphone7值得买吗 知乎 编辑:程序博客网 时间:2024/06/13 22:53

AC通道 :https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3138

[分析]

操作1与操作3显然是简单的加权并查集,而操作2只需要将并查集添上一个移动元素的功能就可以了。

当我们将元素A移动到集合B中时,显然不能直接移动A,否则会将元素A在其原集合中的儿子元素也跟着移动。

这时,我们可以新增一个元素用来代替A,原集合中的A可以只起一个转移的作用,将那个新增的元素与集合B合并即可。

注意:因为这是加权并查集,所以在移动的时候要注意适当增减原集合与新集合的权值。

具体实现方法见代码:

#include <iostream>#include <cstdio>using namespace std;int n,m,cnt;int t[300010];//集合中的元素个数int s[300010];//集合中的权值之和int num[300010];//新增的元素的权值int fa[300010];//fatherint nxt[300010];//保存原元素对应的新增的元素int find(int x){int tmp=x,pre;while(tmp!=fa[tmp])tmp=fa[tmp];while(x!=tmp){pre=fa[x];fa[x]=tmp;x=pre;}return tmp;}void merge(int x,int y){int fx=find(x),fy=find(y);if(fx!=fy){fa[fx]=fy;t[fy]+=t[fx];s[fy]+=s[fx]; }}void move(int x,int y,int real){int fx=find(x),fy=find(y);if(fx==fy)return;cnt++;fa[cnt]=cnt;s[fx]-=num[x];t[fx]--;s[cnt]=num[x];num[cnt]=num[x];t[cnt]=1;nxt[real]=cnt;merge(cnt,fy); }void print(int x){int fx=find(x);printf("%d %d\n",t[fx],s[fx]); }void PENGYIHAO_WORK(){for(int i=1;i<=m;i++){int a,b,c;scanf("%d%d",&a,&b);if(a==1){scanf("%d",&c);merge(nxt[b],nxt[c]);}else if(a==2){scanf("%d",&c);move(nxt[b],nxt[c],b);}else if(a==3){print(nxt[b]);}}}int main(){while(scanf("%d%d",&n,&m)!=EOF){for(int i=1;i<=n;i++)fa[i]=i,s[i]=i,t[i]=1,num[i]=i,nxt[i]=i;cnt=n;PENGYIHAO_WORK();}return 0;}


1 0
原创粉丝点击