洛谷 P1196 [NOI2002] 銀河英雄傳說

_Yxc發表於2024-04-04

題意: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';
            }
        }
    }
}