题解:P14329 [JOI2022 预选赛 R2] 交易计划 / Trade Plan

· · 题解

思路

先将同色连通块用并查集维护,将连接异色连通块的边记录下来。离线询问,对于每两种颜色的连通块暴力加边,并查集维护即可。

code

#include <bits/stdc++.h>

using namespace std;

const int N = 4e5 + 10;

int n, m, k;
int edge[N][2];
int s[N];
int fa[N];

int find(int u)
{
    if (u == fa[u]) return u;
    return fa[u] = find(fa[u]);
}

vector<int> nod[N];
int cnt;
struct node
{
    int u, v;
    int su, sv;
    int id;
    bool operator<(const node &x) const 
    {
        if (su != x.su) return su < x.su;
        return sv < x.sv;
    }
} edg[N], que[N];
int q;
int res[N];

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= m; ++ i) scanf("%d%d", &edge[i][0], &edge[i][1]);
    for (int i = 1; i <= n; ++ i) scanf("%d", &s[i]), fa[i] = i;
    for (int i = 1, fu, fv; i <= m; ++ i)
    {
        fu = find(edge[i][0]);
        fv = find(edge[i][1]);
        if (s[fu] == s[fv]) fa[fu] = fv;
    }
    for (int i = 1; i <= n; ++ i) 
        if (fa[i] == i) 
            nod[s[i]].push_back(i);
    for (int i = 1; i <= m; ++ i)
    {
        int fu = find(edge[i][0]);
        int fv = find(edge[i][1]);
        if (s[fu] != s[fv]) 
        {
            if (s[fu] > s[fv]) swap(fu, fv);
            edg[ ++ cnt] = (node){fu, fv, s[fu], s[fv], 0};
        }
    }
    sort(edg + 1, edg + cnt + 1);
    scanf("%d", &q);
    for (int i = 1, u, v, fu, fv; i <= q; ++ i)
    {
        scanf("%d%d", &u, &v);
        fu = find(u);
        fv = find(v);
        if (s[fu] > s[fv]) swap(fu, fv);
        que[i] = (node){fu, fv, s[fu], s[fv], i};
    }
    sort(que + 1, que + q + 1);
    int pos = 0;
    for (int i = 1; i <= q; ++ i)
    {
        if (que[i - 1] < que[i])
        {
            for (int j = 0; j < nod[que[i].su].size(); ++ j) fa[nod[que[i].su][j]] = nod[que[i].su][j];
            for (int j = 0; j < nod[que[i].sv].size(); ++ j) fa[nod[que[i].sv][j]] = nod[que[i].sv][j];
        }
        while (!(que[i] < edg[pos + 1]) && pos + 1 <= cnt)
        {
            if (que[i].su != edg[pos + 1].su || que[i].sv != edg[pos + 1].sv) ++ pos;
            else 
            {
                int fu = find(edg[pos + 1].u);
                int fv = find(edg[pos + 1].v);
                fa[fu] = fv;
                ++ pos;
            }
        }
        int fu = find(que[i].u), fv = find(que[i].v);
        if (fu == fv) res[que[i].id] = 1;
        else res[que[i].id] = 0;
    }
    for (int i = 1; i <= q; ++ i) printf("%d\n", res[i]);
    return 0;
}