zoukankan      html  css  js  c++  java
  • 吃瓜题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;
    }
  • 相关阅读:
    公众号开发完整页面2
    公众号开发完整页面1
    公众号开发15【html页面】
    公众号开发【分享功能】
    公众号开发13【生成二维码】
    公众号开发11【模板消息接口】
    ST05 跟踪SQL
    ABAP 动态生成内表的几种方法
    SMARTFORM & SAPScript
    某种业务场景下,将一个工作区的多个字段整理到一个内表中
  • 原文地址:https://www.cnblogs.com/romaLzhih/p/9489844.html
Copyright © 2011-2022 走看看