ZOJ 3789 并查集
Posted Dan__ge
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZOJ 3789 并查集相关的知识,希望对你有一定的参考价值。
题意:只说那几个操作把,L将u与v连接,若u左旋,则v右旋,不会出现不合法的条件,Q问u与v的关系,若已知的条件不能判断在则Unknown,旋转方向不一样则Different,一样则Same,然后还有个查询S,问当前u所在的集合的元素个数,D则为删除,但删除后不改变集合其它元素的关系
思路:这题的方向我们可以用到根节点距离来表示,而距离的统计可以直接在路径压缩时完成,元素个数在合并时也可以完成,有点不好想的是这个删除的操作的办法,因为在删除时有可能就将根节点删除了,那么我们可以在找一个数来代替要删除的这个数,而之前的根节点保持不动就行了,加一个数组保存即可
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; typedef unsigned long long ull; const int inf=0x3f3f3f3f; const ll INF=0x3f3f3f3f3f3f3f3fll; const int maxn=1000010; int f[maxn],dis[maxn],num[maxn],ff[maxn]; int find1(int x){ if(x==f[x]) return f[x]; int t=f[x]; f[x]=find1(f[x]); dis[x]+=dis[t]; return f[x]; } void unite(int a,int b){ int aa=find1(a); int bb=find1(b); if(aa==bb) return ; f[aa]=bb; num[bb]+=num[aa]; dis[a]=dis[b]+1; } int main(){ int n,m,u,v; char ch[10]; while(scanf("%d%d",&n,&m)!=-1){ for(int i=0;i<=maxn;i++){ f[i]=ff[i]=i;dis[i]=0;num[i]=1; } for(int i=0;i<m;i++){ scanf("%s",ch); if(ch[0]=='L'){ scanf("%d%d",&u,&v); unite(ff[u],ff[v]); }else if(ch[0]=='Q'){ scanf("%d%d",&u,&v); if(find1(ff[u])!=find1(ff[v])) printf("Unknown\n"); else if(dis[ff[u]]%2==dis[ff[v]]%2) printf("Same\n"); else printf("Different\n"); }else if(ch[0]=='S'){ scanf("%d",&u); int ans=find1(ff[u]); printf("%d\n",num[ans]); }else if(ch[0]=='D'){ scanf("%d",&u); int ans=find1(ff[u]); num[ans]--; ff[u]=++n; num[n]=1;f[n]=n;dis[n]=0; } } } return 0; }
以上是关于ZOJ 3789 并查集的主要内容,如果未能解决你的问题,请参考以下文章
Connections in Galaxy War ZOJ - 3261 离线操作+逆序并查集 并查集删边
Welcome Party ZOJ - 4109 (思维+并查集)
ZOJ3261 Connections in Galaxy War —— 反向并查集