NOI2002 带权并查集

题意:共有30000个人,编号为1-30000,开始时每个人一列。然后进行两种操作:M i j表示把第i个人所在的列的队首加到第j个人所在的列的队尾。C i j查询第i个人和第j个人是否在一列,假如在一列询问i和j间隔着几个人。

题解:

1.不同于以前的带权并查集,这个除了fa数组和d数组外,加了一个num数组,num[i]表示第i列为队首的队列有几个人d[i]表示i到队首有几个人

#include<bits/stdc++.h>
using namespace std ;
#define N 30005
typedef long long ll ; 
int t ;
int fa[N] ;
int d[N] ;//d[i]表示第i个人到队首有几个人。 
int num[N] ;//num[i]表示以第i个人为队首有几个人。 
void init()
{
    int i ;
    for(i = 1 ; i <= N - 5 ; i ++)
    {
        fa[i] = i ;
        d[i] = 0 ;
        num[i] = 1 ;
    }
}
int get(int x)
{
    int temp ;
    if(fa[x] == x)
      return x ;
    temp = fa[x] ;
    fa[x] = get(fa[x]) ;
    d[x] += d[temp] ; //边权相加,因为路径压缩,所以只会累加一次,不用担心多次累加。 
    return fa[x] ;
}
void merge(int x , int y)
{
    int a = get(x) , b = get(y) ;
    d[a] = num[b] ;
    num[b] += num[a] ; //两个队列连接时进行num数组的累加。 
    fa[a] = b ; 
}
void query(int x , int y)
{
    if(get(x) != get(y))
    {
        printf("-1\n") ;
        return ;
    }
    printf("%d\n" , abs(d[x] - d[y]) - 1) ;
}
int main()
{
   int i , j ;
   char s[2] ;
   int x , y ;
   scanf("%d" , &t) ;
   init() ;
   while(t --)
   {
     scanf("%s%d%d" , s , &x , &y) ;	
     if(s[0] == 'M')
     	merge(x , y) ;
     else
     	query(x , y) ;
   }	
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值