并查集删除(转)

并查集的删除---WOJ 1403: Quick Answer

 

连续想了好几天的题=。=,晚上跟人讨论过后终于AC了.

在本题中,需要删除一些元素,而又不希望被删除的元素(记为d)的改变影响到其他和 d 在同一组的元素(比如d是所有同组元素的祖先)
因此可以另外开一个数组 pid[], pid[i]存放的是元素 i 的编号,这个编号在程序运行过程中是逐渐变化的。
当删除了 元素 i 以后,将元素 i 的编号更改为当前最大的编号+1(新的pid[i]),再把parent[i]赋值为新的pid[i]
这样可以使得元素 i 原先的同组元素不受影响,且元素 i 被分配到一个只包含元素 i 的新组。

以上是来自WOJ的提示,当初看这个时,一直对pid[]有疑惑,多亏了hnu的朋友指点后才找到了错误。

对于这题,我的想法是,用use[i]数组标记点 i 是否被删除或没与其它点相连过。

用pid[i]记录点 i 的所属集的编号;

判断时,先看是否为被删除的点,是的话直接no,其次再根据x,y所属集的根编号判断x,y是否在同一集中。

代码如下:


int bin[20001],pid[20001]; 
bool use[20001]; 
int findx(int x)   /* 返回所属团队(编号) */ 
{ 
    int r=pid[x];    /* 关键点,用pid[x]表示x编号 */ 
    while(bin[r]!= r) 
        r=bin[r]; 
    return r; 
} 
void merge(int x,int y) /* 将x,y并到同一集合中 */ 
{ 
    int fx,fy; 
    fx = findx(x); 
    fy = findx(y); 
        bin[fy] = fx; 
} 
int main() 
{   char ch[11]; 
    int n,i,N1=0,N2=0,x,y,fx,fy; 
// freopen("2.txt","r",stdin); 
    while(scanf("%d",&n)!=EOF) 
    {   memset(use,false,sizeof(use)); 
        for(i=0;i<=n;i++) 
        {   bin[i]=i;    /* 初始时,pid[i]和bin[i]都赋为i */ 
            pid[i]=i; 
        } 
        while(scanf("%s",ch)&&ch[0]!='e') 
        {   if(ch[0]=='c') 
            {   scanf("%d%d",&x,&y); 
                use[x]=true; 
                use[y]=true; 
                merge(x,y); 
            } 
            if(ch[0]=='q') 
            {   scanf("%d%d",&x,&y); 
                if((!use[x]||!use[y])&&x!=y) // x!=y 初始时use全为false,当没有相连点直接q 1 1时,需要跳过use判断. 
                    N2++; 
                else 
                {   fx=findx(x); 
                    fy=findx(y); 
                    if(fx==fy) 
                        N1++; 
                    else 
                        N2++; 
                } 
            } 
            if(ch[0]=='d') 
            {   
                scanf("%d",&x); 
                use[x]=false; /* 删除点x,使x自成一组,其编号为当前最大编号+1 */ 
                pid[x]=++n; 
                bin[n]=n; 
            }     
        } 
        printf("%d , %d/n",N1,N2); 
        N1=0;N2=0; 
    } 
    return 0; 
}


在hnu跑了78MS,

将深度小的树合并到深度大的树,将效率优化到0(logN)对速度没有明显优化.

http://hi.baidu.com/abs_rember/blog/item/de0436c5bfcf08d5d00060ad.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值