“我们的征途是星辰大海”
思路:
加权并查集
维护f[i],t[i],cnt[i]
cnt[i]->i在当前队列中后面有多少元素
f[i]->i所在集合标志元素(队列底元素)
注意在未执行find(i)操作时,f[i]不一定为i真正的底
t[i]->i所在队列顶元素
t[i]仅在merge更新不再是队底的元素的cnt值时有意义
需要保证每个元素的f[i]的t、cnt等值时刻为实际值,这样每个元素在find后,t、cnt等可更新为实际值
有点像线段树的lazy思想?
/*
4
M 2 3
C 1 2
M 2 4
C 4 2
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 200000 + 50;
int f[MAXN],t[MAXN],cnt[MAXN];
void init(int n)
{
for(int i = 1;i <= n;i ++)
f[i] = i,t[i] = i;
}
int n;
int find(int x)
{
if(x == f[x])return x;
int fa = f[x];
f[x] = find(f[x]);
cnt[x] += cnt[fa];
return f[x];
}
void merge(int a,int b)
{
a = find(a);b = find(b);
find(t[b]);//t[b]不为标志元素,其值不一定为实际值
cnt[a] = cnt[t[b]] + 1;
f[a] = b;
t[b] = t[a];
}
char ch;
int x,y;
int main()
{
cin >> n;
init(30000);
for(int i = 1;i <= n;i ++)
{
cin >> ch >> x >> y;
if(ch == 'M')
{
merge(x,y);
}
else
{
find(x);find(y);
if(f[x] != f[y])
{
cout << -1 << '\n';
}
else
{
if(cnt[x] < cnt[y])swap(x,y);
cout << cnt[x] - cnt[y] - 1 << '\n';
}
}
}
}
好像18年要重新动画化?emmmmm