1 条题解

  • 0
    @ 2025-10-19 23:05:50

    题目解析 这道题要求找出所有可能成为最终统一颜色的初始村庄。关键规则是:一个村庄只能说服相邻村庄,当且仅当它的支持者数量不少于目标村庄的支持者数量。

    核心思路

    1. 问题转化 将问题看作:从最终状态反向推导,哪些初始颜色可能通过合法的说服过程统一全岛。

    2. 关键观察 如果一个连通分量可以"吞并"相邻的连通分量,那么整个分量可以统一颜色

    按村庄人口从小到大处理,保证处理顺序的合理性

    1. 算法流程 步骤1:初始化

    每个村庄独立为一个连通分量

    记录每个分量的总人口 sum[i]

    维护每个分量的邻居信息 nei[i]

    步骤2:排序处理

    cpp sort(ord, ord + n, [](const int &x, const int &y) { return a[x] == a[y] ? x < y : a[x] < a[y]; }); 按人口从小到大排序,确保处理顺序正确。

    步骤3:增量合并 对于每个村庄 x(按人口升序):

    合并所有人口小于等于 x 的相邻连通分量

    检查当前分量是否能吞并最小邻居:

    cpp if (sum[getf(x)] >= nei[getf(x)].begin()->F) { nt[nei[getf(x)].begin()->S.S].push_back(x); } 如果能吞并,建立有向边表示可达性

    步骤4:传播标记 从人口最大的村庄开始DFS,标记所有可达的村庄:

    cpp dfs(ord[n - 1]); 代码关键部分解析 并查集与启发式合并 cpp void Merge(int x, int y) { // 启发式合并:总是小集合合并到大集合 if (nei[x].size() < nei[y].size()) swap(x, y);

    // 合并邻居信息
    for (auto &[w, e] : nei[y]) {
        if (getf(e.S) == x)
            nei[x].erase(make_pair(a[e.F], make_pair(e.S, e.F)));
        else
            nei[x].insert(make_pair(w, e));
    }
    
    fa[y] = x;
    sum[x] += sum[y];  // 合并人口总数
    

    } 邻居信息维护 nei[x] 存储格式:{邻居人口, {当前节点, 邻居节点}}

    使用 set 自动按人口排序,方便找到最小邻居

    在合并时更新邻居关系

    可达性传播 cpp void dfs(int x) { vis[x] = true; for (auto &y : nt[x]) if (!vis[y]) dfs(y); } 从最大人口村庄开始传播,标记所有可能统一全岛的颜色。

    算法复杂度 排序:O(nlogn)O(n \log n)

    并查集操作:O(nα(n))O(n \alpha(n))

    启发式合并:O(mlogn)O(m \log n)

    总体:O((n+m)logn)O((n + m) \log n)

    样例验证 样例1:村庄人口 [2,2,4,3]

    按人口排序:1(2), 2(2), 4(3), 3(4)

    处理过程:

    村庄1:合并相邻小人口村庄

    村庄2:继续合并

    村庄4:检查是否能吞并邻居

    村庄3:作为最大人口,开始传播标记

    输出:1110(只有村庄4不能统一全岛)

    样例2:类似处理,输出1110

    这种方法巧妙地利用离线处理+并查集+贪心,高效解决了颜色统一的可达性问题。

    • 1

    「BalticOI 2022 Day2」Stranded Far From Home

    信息

    ID
    3545
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者