zoukankan      html  css  js  c++  java
  • HDU

    HDU - 6109 数据分割 并查集启发式合并

    题意

    一个程序会接受如(x_i = x_j)或者(x_i eq x_j)的条件表示式。

    现给出(L)行,碰到某一行发现矛盾则输出这一串表达式的个数,开启新的表达式。

    e = 1 表示相等,0表示不相等

    [i,j,L leq 100000\ x_i , x_j leq L ]

    分析

    联系之前洛谷做过的一道题,很容易想到这题用并查集来做。

    我们可以把相等的点合并到一个并查集。

    若遇到不等于,如果两点在同一个并查集,那么输出错误。如果不在同一个并查集,为了标记,在两个并查集的根之间连一条边,表示一种关系。

    若遇到相等,如果两个点不在一个并查集,且已经有连边,则输出错误。

    否则我们把两个并查集合并,注意这时候就要把边数较小的集合合并到另一个集合,这就是所谓的启发式合并。

    这样每个点合并一次规模至少扩大两倍,复杂度就会是(NlogN)的。

    不妨用(set)来支持快速删边加边操作。

    代码

    int pre[maxn];
    set<int> e[maxn];
    vector<int> ans;
    
    int Find(int x) {
        return pre[x] != x ? pre[x] = Find(pre[x]) : x;
    }
    
    bool Union(int p, int q) {
        if (p != q) {
            if (e[p].size() > e[q].size())
                swap(p, q);
            for (auto it : e[p]) {
                if (it == q) return false;
                e[it].erase(p);
                e[it].insert(q);
                e[q].insert(it);
            }
        }
        pre[p] = q;
        return true;
    }
    
    
    int main() {
        int L = readint();
        int x, y, ee;
        int Max = -1;
        int siz = 0;
        for (int i = 1; i <= 100000; i++)
            pre[i] = i;
        for (int i = 1; i <= L; i++) {
            x = readint();
            y = readint();
            ee = readint();
            Max = max(Max, x);
            Max = max(Max, y);
            int p = Find(x);
            int q = Find(y);
            if (!ee) {
                if (p == q) {
                    ans.push_back(i - siz);
                    siz = i;
                    for (int i = 1; i <= Max; i++)
                        pre[i] = i, e[i].clear();
                    Max = -1;
                    continue;
                }
                e[p].insert(q);
                e[q].insert(p);
            }
            else if (!Union(p, q)) {
                ans.push_back(i - siz);
                siz = i;
                for (int i = 1; i <= Max; i++)
                    pre[i] = i, e[i].clear();
                Max = -1;
                continue;
            }
        }
        cout << ans.size() << '
    ';
        for (int i = 0; i < ans.size(); i++)
            cout << ans[i] << '
    ';
    }
    
  • 相关阅读:
    Flink Application Development DataStream API Execution Mode (Batch/Streaming)- Flink应用程序开发DataStream API执行模式(批/流)
    Flink Application Development DataStream API Overview
    Flink Concept Stateful Stream Processing -Flink概念有状态流处理
    Hdfs原理
    Leetcode 763 划分字母区间
    406. 根据身高重建队列
    贝叶斯统计概要(待修改)
    蒙特卡罗方法
    马尔科夫链蒙特卡罗方法(MCMC)
    Leetcode452. 用最小的箭引爆气球
  • 原文地址:https://www.cnblogs.com/hznumqf/p/13756637.html
Copyright © 2011-2022 走看看