顾名思义,就是并查集带权值。
在路径压缩的时候,我们还要维护权值应该怎么办呢?
关联题目:P1196 [NOI2002] 银河英雄传说。
我们对于一个舰队维护一个 $fr$ 表示到头部的距离,$cnt$ 表示该舰队的战舰数量。那么每一次合并时,先进行路径压缩,找到父亲,在将父亲的权值传下来即可。因为每一次合并都是从被合并的节点传下来,所以不会有重复。
如果还不明白的请看图:
| | |
| ------------ | ------------ |
| | |
如图,我们将 $4$ 所在的连通块合并到 $3$ 所在的连通块,那么 $\{4,5,6\}$ 会被合并到 $1$ 的儿子,大小也根据 $1$ 所在的连通块大小更新。但是这样的话我们就要控制 find()
函数的使用。
int fa[maxn],fr[maxn],cnt[maxn];
int find(int x) {
if(fa[x]==x) return x;
int X=find(fa[x]);
fr[x]+=fr[fa[x]];
return fa[x]=X;
}
int T;
signed main() {
For(i,1,30000) {
fa[i]=i;
fr[i]=0;
cnt[i]=1;
}
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--) {
char ch;
int x,y;
cin>>ch>>x>>y;
int X=find(x),Y=find(y);
if(ch=='M') {
fa[X]=Y;
fr[X]+=cnt[Y];
cnt[Y]+=cnt[X];
} else {
if(X!=Y) cout<< -1<<'\n';
else cout<<abs(fr[x]-fr[y])-1<<'\n';
}
}
}