poj1988

题意:有n个元素,开始每个元素自己一栈,有两种操作,将含有元素x的栈放在含有y的栈的顶端,合并为一个栈。第二种操作是询问含有x元素下面有多少个元素。

分析:并查集,因为当我们知道栈中元素的总数,和某元素到栈顶的距离,我们就能知道这个元素下面有多少元素。我们并操作的时候,始终使用在上面栈的代表元来做合并之后的代表元,这样也就达到了栈中的代表元是栈中的堆顶元素的效果,我们只需在每个代表元中记录该栈中的元素总数即可。然而我们还需要得知某元素到代表元的距离,这样我们就需要记录每个元素到其父亲的距离,把它到代表元上所经过的距离加起来,即为它到代表元的距离。这样我们就得出了结果。另外优化的过程(把路上所有元素的father改为代表元的过程)比较复杂,容易错。

View Code
#include <iostream>
#include
<cstdlib>
#include
<cstring>
#include
<cstdio>
usingnamespace std;

#define maxn 30003

struct Block
{
int father, tot, dis;
}block[maxn];

int n;

void init()
{
for (int i =0; i < maxn; i++)
{
block[i].father
= i;
block[i].tot
=1;
block[i].dis
=0;
}
}

int getanc(int a)
{
int ret;
if (block[a].father == a)
return a;
ret
= getanc(block[a].father);
block[a].dis
+= block[block[a].father].dis;
block[a].father
= ret;
return ret;
}

void move()
{
int a, b;
scanf(
"%d%d", &a, &b);
int anc1 = getanc(a);
int anc2 = getanc(b);
block[anc2].dis
= block[anc1].tot;
block[anc2].father
= anc1;
block[anc1].tot
= block[anc1].tot + block[anc2].tot;
}

void count()
{
int a;
scanf(
"%d", &a);
int anc = getanc(a);
printf(
"%d\n", block[anc].tot - block[a].dis -1);
}

int main()
{
//freopen("D:\\t.txt", "r", stdin);
scanf("%d", &n);
init();
for (int i =0; i < n; i++)
{
char st[3];
scanf(
"%s", st);
if (strcmp(st, "M") ==0)
move();
else
count();
}
return0;
}
原文地址:https://www.cnblogs.com/rainydays/p/1982677.html