poj 1988_并查集(*)

来源:互联网 发布:java通过ip获取地区 编辑:程序博客网 时间:2024/06/04 22:02

题目描述:

   。。。。。tle了数次。。。  

解题思路:

  几个可以看出来属于并查集的题,但是有时效要求。如果没有时效要求的话,一个最直观的方法是可以直接用不压缩的并查集,最后找树的某个节点位于第几层即可;如果压缩的话,也可以加一个down[]数组来存要求的值,在每次做union的时候,把x点放在y点之上时更新所有x点所在子树的所有down值,但是这样更新耗费的时间大,会令整个复杂度就增加为n倍的原并查集的复杂度;因此需要想一想,如果开两个数组up[]和down[],每次union的时候,只更新底层子树根的down值,和底层子树根的up值(也就是每次合并之前,子树根的up和down值都是正确的),然后在最后求的时候,用find_set更新点的up值,令根down值减去节点的up值,即为节点的深度。

代码:

#include <stdio.h>
#include <stdlib.h>
#define N 30001

int set[N], down[N], up[N];
int count, max=1;

int find_set(int x)
{
   int tmp = set[x];
   if(set[x]!=x)
   {
     set[x] = find_set(set[x]);
     printf("find_set中更新:up[%d](%d) +=up[%d](%d).\n",x,up[x],tmp,up[tmp]);
     up[x] += up[tmp];
     printf("find_set中更新后:up[%d] = %d.\n",x,up[x]);
   }
   return set[x];
}
void union_set(int x, int y) // m x y
{
   int i;
   int y1 = find_set(y);
   int x1 = find_set(x);
//  for(i=1;i<=max;i++) //x所在的树的每个点的down都要加上 1+down[y1]
//     if(find_set(i) == x1)
//     {
//       // printf("顶层树的%d点的原值(%d) 加上 底层树的最高值(1+y1[%d点]) %d =",i,down[i],y1,1+down[y1]);
//        down[i] += 1+down[y1];
//        //printf("%d.\n",down[i]);
//     }
   set[y1] = x1;
  printf("归并%d(x)->%d(y)上,令set[%d](y1) =%d(x1).\n",x,y,y1,x1);
   printf("更新前:x1:down[%d] =%d.\ty1:up[%d] = %d,down[%d] =%d\n",x1,down[x1],y1,up[y1],y1,down[y1]);
   up[y1] += down[x1];
   down[x1] += down[y1];
   printf("更新后:x1:down[%d] =%d.\ty1:up[%d] = %d,down[%d] =%d\n",x1,down[x1],y1,up[y1],y1,down[y1]);
}

main()
{
   int p,i,x,y;
   char str[2];
  
  scanf("%d",&p);
  
  for(i=1;i<N;i++)
   {
     set[i] = i;
     down[i] = 1;
     up[i] = 0;
   }
  
  for(i=1;i<=p;i++)
   {
     scanf("%s",str);
     if(strcmp("M",str)==0)
     {
        scanf("%d %d",&x,&y);
        max =max>x?(max>y?max:y):(x>y?x:y);
        union_set(x,y);
     }
     else
     {
        
        scanf("%d",&x);
        count = down[find_set(x)]-up[x];
        printf("%d\n",count-1);
     }
   }
   //system("pause");
   return 0;
}

 

原创粉丝点击