2020牛客暑期多校训练营(第三场)G Operating on a Graph

q个操作,每次将和 o i o_i oi相连的点都染成和 o i o_i oi一样的颜色,求最终每个点所属的集合。 ( n , q ≤ 2 × 1 0 5 ) (n,q\leq2\times10^5) (n,q2×105)
重要观察:只要一个点被归入一个集合,他们之后是一直相连的。

用一个链表存储所有与 u i u_i ui相连的点,每次将所有与 e [ o i ] e[o_i] e[oi]中的点相连的点都染入 o i o_i oi的集合即可。

#include
#define mem(ss) memset(ss,0,sizeof(ss))
#define rep(d, s, t) for(int d=s;d<=t;d++)
#define rev(d, s, t) for(int d=s;d>=t;d--)
#define inf 0x3f3f3f3f
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef double db;
typedef std::pair<int, int> pii;
typedef std::pair<ll, ll> pll;
typedef std::pair<double, double> pdd;
const double eps = 1e-6;
const ll mod = 1e9 + 7;
const int N = 8e5 + 10;
#define io_opt ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;

ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }

int fa[N];

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

vector<int> e[N];

int main() {
    io_opt;
    int t;
    cin >> t;
    while (t--) {
        int n, m;
        cin>>n>>m;
        for (int i = 0; i < n; i++) {
            fa[i] = i;
            e[i].clear();
        }
        while (m--) {
            int x, y;
            cin>>x>>y;
            e[x].push_back(y);
            e[y].push_back(x);
        }
        int q;
        cin>>q;
        while (q--) {
            int o;
            cin>>o;
            if (find(o) == o) {
                vector<int> p = e[o];
                e[o].clear();
                for (int i : p) {
                    int u = find(i);
                    if (u != o) {
                        fa[u] = o;
                        if(e[o].size() < e[u].size()) swap(e[u],e[o]);//不这样写会莫名MLE
                        for (int j : e[u])
                            e[o].push_back(j);
                    }
                }
            }
        }
        for (int i = 0; i < n; i++)
            cout << find(i)<<' ';
        cout<<endl;
    }
    return 0;
}

你可能感兴趣的:(并查集)