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;
}
评论