想了几中办法,甚至加入了后继结点,但是一直超时,最后参考了网上代码。原文地址:http://www.cppblog.com/MiYu/archive/2010/08/26/124771.html
题目分析:
题目的意思大概就是 有N 封邮件, 编号 0 -> N-1, 然后有2种操作, M : 合并操作, 将 2 种邮件合并为一种.S : 分离操作, 将一封邮件独立出去, 单独占一个集合.
最后题目要求统计 集合的 个数. 从这里可以很容易的看出, 这是一个 并查集的题目, 不过按朴素方法来做的话, 一般都会 TLE.
加上数据量很大 , 不要使用 cin , 会超时. 而且一般来说 G ++ 和 C++ 在处理大量数据的时候会有1倍的时差 !!! 所以一般建议使用
C++ 提交代码.
#include <iostream>
#include <algorithm>
using namespace std;
int set[1350005];
int a[125000];
int N,M;
int inline find ( int x )
{
return x != set[x] ? set[x] = find ( set[x] ) : set[x];
}
void inline merge ( int x, int y )
{
x = find ( x );
y = find ( y );
if ( x == y ) return ;
set[x] = y;
}
int main ()
{
freopen("2473.txt", "r", stdin);
int ca = 1;
while ( scanf ( "%d%d",&N,&M ), M || N )z
{
for ( int i = 0; i < N; ++ i )
set[i] = i+N;
for ( int i = N; i <= N + N + M; ++ i )
set[i] = i;
// 这是关键, 虽然空间的消耗比较大, 但是节省了大量时间, 这样处理的目的是将0 -> N-1 的 节点处理成叶子节点
// 这样在对这些 节点做 S 操作的时候就不会影响到其他的节点, 而 find 操作是带路径压缩的, 所以就保证了我们所 // 有要处理的节点一直是叶子节点 !!!
int sep = N + N;
int x,y; char ch[5];
for ( int i = 0; i != M; ++ i )
{
scanf ( "%s",ch );
switch ( ch[0] )
{
case 'M': scanf ( "%d%d",&x,&y ); merge ( x,y ); break;
case 'S': scanf ( "%d",&x ); set[x] = sep ++; break; //初始化操作就是为这一步准备的
}
}
for ( int i = 0; i != N; ++ i )
a[i] = find ( i );
sort ( a, a + N );
int nCount = 1;
for ( int i = 1; i < N; ++ i )
if ( a[i] != a[i-1] ) nCount ++;
printf("Case #%d: %d\n",ca++,nCount);
}
return 0;
}