吃瓜题2(虚拟分类并查集+启发式合并)

题意:
与吃瓜题1题意一致,只是西瓜的种类从两种变成了无数种。

题解:
在吃瓜题1里,由于只有两类西瓜,因此我们可以使用分类的方法来表示异同。而在这题中,由于种类数无穷,我们只有记录每个节点的对立节点,在询问x与y的关系时,我们查询x的对立节点集合中是否出现y节点。
那么如何记录对立节点集呢?我们采用set

当两个节点确定异种的时候,我们分别在set[x]和set[y]中添加y和x
当两个节点确定同种的时候,我们将他们的set合并到一起。合并是要注重技巧的!每次,我们选择较小的set,添加到较大的set中。因此,最坏情况其实就类似于一个二叉树的合并次数,大约为N次。

#include<cstdio>
#include<set>
using namespace std;

const int maxn = 1e6 + 5;
int pre[maxn];
set<int>diff[maxn];

int findset(int x) {
    if (x == pre[x]) return x;
    else return pre[x] = findset(pre[x]);
}

void unionset(int x,int y) {
    int fx = findset(x);
    int fy = findset(y);
    if (diff[fx].size() < diff[fy].size()) {
        //swap(fx, fy);
        pre[fx] = fy;
        for (set<int>::iterator it = diff[fx].begin(); it != diff[fx].end(); it++) {
            int tmp = *it;
            tmp = findset(tmp);
            diff[fy].insert(tmp);
            diff[tmp].insert(fy);
        }
    }
    else {
        //swap(fx, fy);
        pre[fy] = fx;
        for (set<int>::iterator it = diff[fy].begin(); it != diff[fy].end(); it++) {
            int tmp = *it;
            tmp = findset(tmp);
            diff[fx].insert(tmp);
            diff[tmp].insert(fx);
        }
    }
}

int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 0; i <= n; i++) {
        pre[i] = i;
    }
    while(m--) {
        char s[3];
        int x, y, id;
        scanf("%s", s);
        if (s[0] == 'A') {
            scanf("%d%d%d", &x, &y, &id);
            if (id == 1) {
                unionset(x, y);
            }
            else {
                int fx = findset(x);
                int fy = findset(y);
                diff[fx].insert(fy);
                diff[fy].insert(fx);
            }
        }
        else {
            scanf("%d%d", &x, &y);
            int fx = findset(x);
            int fy = findset(y);
            if (fx==fy) printf("1
");
            else if (diff[fx].find(fy) != diff[fx].end()) 
                printf("2
");
            else printf("3
");
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/romaLzhih/p/9489844.html