POJ1988
原题链接https://vjudge.net/contest/350953#problem/E
有1-n个方块,题目操作为将x的方块所在位置的所有方块放到y上面。最后求方块下面有多少个方块。在这里使用并查集来做
对于样例
1 6
2 4
2 6
首先把1放到6上面,2放到4上面,之后要进行 对1 2 的合并。
也就是将2 放到 1上面
我们以最上面的方块作为并查集的根,我们可以计算的是下面方块到根的距离以及当前集团有多少个方块
在合并之后我们显然可以得到2集团拥有了4个方块4-2距离为1
那么我们求4下面有多少就是求
即4-1-1(减去跟所占的1);即为4方块下面的方块的数量。
使用vis来记录方块的数量,re来录权值。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
long long pre[30005];
long long vis[30005];
long long re[30005];
long long find(long long x)
{
if(x==pre[x])
{
return x;
}
long long t=pre[x];
pre[x]=find(pre[x]);//压缩路径
re[x]+=re[t];//合并时计算距离
return pre[x];
}
void join(long long x,long long y)
{
long long ss1=find(x);
long long ss2=find(y);
// printf("%lld %lld\n",ss1,ss2);
if(ss1!=ss2)
{
pre[ss2]=ss1;
re[ss2]=vis[ss1];//将另一个集团全部放到ss2上面,那么ss2到最上方方块的距离显然就是另一个集团有多少方块。
vis[ss1]+=vis[ss2];//将两个集团加起来,更新根的集团的数量
}
}
int main()
{
long long i,n;
scanf("%lld",&n);
for(i=0; i<=30000; i++)//初始根为自己,集团只有自己一个方块,路径为0;
{
pre[i]=i;
vis[i]=1;
re[i]=0;
}
while(n--)
{
char s;
long long x,y,c;
getchar();
scanf("%c",&s);
//printf("%c ",s);
if(s=='M')//判断题目的操作
{
scanf("%lld %lld",&x,&y);
// printf("%lld %lld\n",x,y);
join(x,y);//合并
}
else
{
scanf("%lld",&c);
long long ss1=find(c);//压缩路径,更新权值。
long long sum1=vis[ss1]-1-re[c];//计算答案。
printf("%lld\n",sum1);
// printf("%lld\n",c);
}
} /*
for(i=1; i<7; i++)
{
find(i);
printf("%lld ",pre[i]);
}
cout<<endl;
for(i=1; i<7; i++)
{
find(i);
printf("%lld ",re[i]);
}*/
return 0;
}