题目意思是有30000个cube,每次执行
M I J,就是将有I 的一堆放在有J的一堆上面
执行
C I 询问I的下面有几个cube
不会出现同一堆的转移这种情况
由于使用并查集,记录了秩的大小,既每一个真根下的cube个数,故down值是很容易求的。所以要解决的,就是从节点到真根的路径的节点数,故堆下的cube个数为down[ root ] - up[i] - 1( root 为i的真根 )
AC code
Memory: 508K | Time: 282MS |
#include <iostream>
using namespace std;
const int NMAX = 30050;
int P,i,j;
int father[NMAX],up[NMAX],down[NMAX];
void makeset()
{
for( i=1; i<=30000; i++ ){
father[i] = i;
up[i] = 0;
down[i] = 1;
}
}
int find( int x )
{
if( x != father[x] ){
int temp = father[x];
father[x] = find( father[x] );
up[x] += up[temp]; //路径压缩同时加上父节点的up数
}
return father[x];
}
void link( int x , int y )
{
x = find( x );
y = find( y );
father[y] = x;
up[y] = down[x] ; //up 数 等于 down的数目
down[x] += down[y];
}
void move()
{
int x , y ;
scanf( "%d %d", &x , &y ) ;
link( x , y );
}
void ask()
{
int Qes;
scanf( "%d", &Qes);
int root = find( Qes );
printf( "%d/n", down[root] - up[Qes] - 1 ) ;
}
int main()
{
scanf( "%d", &P );
getchar();
makeset();
while( P -- ){
char c = getchar();
if( c == 'M' ) move();
else ask();
getchar();
}
return 0;
}
这里有个不错的操作,既father[y] = x ; up[y] = down[x];这样就使得两堆东西合并了一起,但之前y堆下的元素依然指向y
而不是指向x,在询问的过程中会进行一次路径压缩,所以会运行up[x] += up[ father[x] ],导致数的up值正确无误。