首先普通并查集大家都诙谐。。。
#include<bits/stdc++.h>
using namespace std;
int fa[1111111],i,j,x,y,z,m,rk[1111111];
int finds(int xx)
{
if(fa[xx]==xx) return xx;
else return finds(fa[xx]);
}
void unions(int xx,int yy)
{
int xxx=finds(xx),yyy=finds(yy);
if(xxx==yyy) return;
else
{
fa[xxx]=yyy;
}
}
int main()
{
scanf("%d",&m);
for(i=1;i<=m;i++)
{
scanf("%d",&x);
if(x==1)
{
scanf("%d",&y);
fa[y]=y;
}
else if(x==2)
{
scanf("%d%d",&y,&z);
unions(y,z);
}
else
{
scanf("%d%d",&y,&z);
int yy=finds(y),zz=finds(z);
if(yy==zz) printf("Y\n");
else printf("N\n");
}
}
}
这里有两个优化,
1,路径压缩
顾名思义,上代码。。。
int finds(int xx)
{
if(fa[xx]==xx) return xx;
else return fa[xx]=finds(fa[xx]);
}
快乐亨多,但破坏了原本的结构,要看题目情况!!!
2,按秩合并
再次顾名思义,再次上代码。。。
void unions(int xx,int yy)
{
int xxx=finds(xx),yyy=finds(yy);
if(xxx==yyy) return;
if(rk[xxx]>rk[yyy]) fa[yyy]=xxx;
else
{
fa[xxx]=yyy;
if(rk[xxx]==rk[yyy])
{
rk[yyy]++;
}
}
}
这个可以放心私用。。。
总结一下:
#include<bits/stdc++.h>
using namespace std;
int fa[1111111],i,j,x,y,z,m,rk[1111111];
int finds(int xx)
{
if(fa[xx]==xx) return xx;
else return fa[xx]=finds(fa[xx]);
}
void unions(int xx,int yy)
{
int xxx=finds(xx),yyy=finds(yy);
if(xxx==yyy) return;
if(rk[xxx]>rk[yyy]) fa[yyy]=xxx;
else
{
fa[xxx]=yyy;
if(rk[xxx]==rk[yyy])
{
rk[yyy]++;
}
}
}
int main()
{
scanf("%d",&m);
for(i=1;i<=m;i++)
{
scanf("%d",&x);
if(x==1)
{
scanf("%d",&y);
fa[y]=y;
rk[y]=1;
}
else if(x==2)
{
scanf("%d%d",&y,&z);
unions(y,z);
}
else
{
scanf("%d%d",&y,&z);
int yy=finds(y),zz=finds(z);
if(yy==zz) printf("Y\n");
else printf("N\n");
}
}
}
加权主要在用并查集维护权值数组即可。。。(逃
至于删除,上代码!!!
void ycl()
{
ie=n;
for(int i=1;i<=n;i++)
{
ie++;
fa[i]=ie;
}
for(int i=n+1;i<=2*n;i++)
{
fa[i]=i;
}
}
void del(int xx)
{
ie++;
fa[xx]=(ie);
fa[ie]=ie;
}