正文

Zoj 2833 Friendship2008-01-22 18:40:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/cruxd/32353.html

分享到:

2730205 2008-01-22 18:15:30 Accepted 2833 C++ 00:00.95 1180K C.D.

 

这大概就是所谓的RPWT,拿出来炫耀一下。【灰溜溜爬开】

其实这题的时限是3000ms,还宽裕的很。但前十名都能把时间压到500ms以内,说明普通的并查集还有值得优化的地方。顺便讲一句,这题通过的人数好X多。第一次写的时候根本就忘了什么是压缩路径,可耻地TLE鸟。【= =】 发现上一次写并查集是一年前的事情,结果又忘记怎么做了……【为什么是又】

所谓的并查集,也只不过是一枚特殊的树罢了。这棵树在完成findset操作之后,高度至多为2,而且形式为根节点下面N个叶子——这就是压缩;在完成两棵树的合并之后高度至多为3.为了方便编写,采用的是数组而不是链表;这一点我倒是牢牢记住了。

/* zoj 2833
 author : Crux.D
 date : 2008.1.21
 description : unionset
*/

#include <cstdio>
#include <string>

int parent[100001], num[100001], N, M, cs = 0;

void init ()
{
 int i;
 for ( i = 0; i <= N; i ++ )
 {
  parent[i] = -1;
  num[i] = 1;
 }
 if ( cs ++ )
  printf ( "\n" );
 printf ( "Case %d:\n", cs );
}

int find_set ( int n )
{
 //寻找树的根节点
 int pre = n;
 while ( parent[pre] != -1 )
 {
  pre = parent[pre];
 }
 int root = pre;
 //非递归从底到顶压缩路径,简化为高度为2的树
 while ( n != root )
 {
  int t = parent[n];
  parent[n] = root;
  n = t;
 }
 return root;  

int union_set ( int n1, int n2 )
{
 int t1 = find_set ( n1 );
 int t2 = find_set ( n2 );
 //合并之后树的高度为3,小树合至大树
 if ( t1 == t2 )
  return 0;
 if ( num[t1] < num[t2] )
 {
  parent[t1] = t2;
  num[t2] += num[t1];
 }
 else
 {
  parent[t2] = t1;
  num[t1] += num[t2];
 }
 return 0;
}

void query_friend ( int n )
{
 int t = find_set ( n );
 printf ( "%d\n", num[t] );
}

int main ()
{
 //freopen ( "in.txt", "r", stdin );
 
 while ( scanf ( "%d %d ", &N, &M ) != EOF )
 {
  int i;
  init ();
  for ( i = 0; i < M; i ++ )
  {   
   char ch;
   int t1, t2 = 0;
   scanf ( "%c", &ch );
   if ( ch == 'M' )
   {
    scanf ( "%d %d ", &t1, &t2 );
    union_set ( t1, t2 );
   }
   else
   {
    scanf ( "%d ", &t1 );
    query_friend ( t1 );
   }
   //pt ();
   //printf ( "%c %d %d\n", ch, t1, t2 );
  }  
 }

 return 0;
}

阅读(2911) | 评论(1)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册