银河英雄传说
题目
解析
这道题目很明显是使用并查集,但这里要引入一种新的并查集:
边带权的并查集
这里的权,可以是很多东西,如距离等
那么这题为什么一定要用这一种呢?
假如不路径压缩,明显可以轻易求出,但是有一个大问题
超时
至于按秩合并,应该看一看以下文字:
含义为第i号战舰所在的整个战舰队列,作为一个整体(头在前尾在后)接至第j号战舰所在的战舰队列的尾部。
合并有向,不能按秩合并
思路:
用三个数组分别存储这个节点的父亲,这个节点到父亲的距离,以及以这个节点为代表的连通块大小(不是代表则无效)
code:
#include<cstdio>
#include<cstring>
using namespace std;
char t;
int x,y,xx,yy,f[30010],c[30010],d[30010],q;
int abs(int dep){
return (dep>-dep)?dep:-dep;}
bool isdigit(char t){
return (t<='9'&&t>='0')?1:0;}
int find(int dep)
{
if(f[dep]==dep)return dep;
int l=find(f[dep]);
c[dep]+=c[f[dep]];//累加路径影响
return f[dep]=l;
}//查询(路径压缩)
inline int read()
{
int num=0,f=1;
char c=0;
while(!isdigit(c=getchar())){
if(c=='-')f=-1;}
while(isdigit(c))num=(num<<1)+(num<<3)+(c&15),c=getchar();
return num*f;
}//快读
int main()
{
for(int i=1;i<=30000;i++)f[i]=i,d[i]=1;
q=read();
while(q--)
{
scanf(" %c ",&t);
x=read(),y=read();
if(t=='M')
{
xx=find(x),yy=find(y);
c[xx]=d[yy];//让原以c为代表的节点获得正确的距离
d[yy]+=d[xx];//大小增加
f[xx]=yy;//改变父节点
}
else
{
if(find(x)!=find(y))printf("-1\n");
else printf("%d\n",abs(c[x]-c[y])-1);
}
}
return 0;
}