題意:30000列軍隊,每列初始有1個。編號從1~30000.每次操作有兩種,將現在第i列所在的列合併到第j列所在列的末尾。 或者查詢第i列舉例第j列的距離。
思路:帶權並查集。合併時將第i列頭節點接到第j列頭節點上。然後直接查詢dist取絕對值相減就好。
總結:一開始沒看清題,以為要把從i列從當前所在列中擷取出來接到第j列所在列末尾,就多了一個i列隊頭減i列元素數量的情況。
class DisjointSet{
public:
DisjointSet(int sz): sz_(sz){
fa_.resize(sz_);
iota(fa_.begin(), fa_.end(), 0);
set_size_.assign(sz_, 1);
dist_.assign(sz_, 0);
}
int findSet(int x){
if (fa_[x] == x){
return x;
}
return updateDist(x), fa_[x];
}
bool isSameSet(int x, int y){
return findSet(x) == findSet(y);
}
void unionSet(int x, int y){
int px = findSet(x);
int py = findSet(y);
fa_[px] = py;
dist_[px] = set_size_[py];
set_size_[py] += set_size_[px];
}
int getDist(int x){
updateDist(x);
return dist_[x];
}
private:
int sz_;
vector<int> fa_;
vector<int> set_size_;
vector<int> dist_;
inline void updateDist(int x){
if (fa_[x] == x){
return;
}
int par = fa_[x];
fa_[x] = findSet(fa_[x]);
dist_[x] += dist_[par];
}
};
void solve(){
int q;
cin >> q;
DisjointSet dsu(300010);
while (q --){
char t;
cin >> t;
int i, j;
cin >> i >> j;
if (t == 'M'){
dsu.unionSet(i, j);
}
else{
if (dsu.isSameSet(i, j) == false){
cout << -1 << '\n';
}
else{
cout << abs(dsu.getDist(j) - dsu.getDist(i)) - 1 << '\n';
}
}
}
}