1 条题解
-
0
题目解析 这道题要求找出所有可能成为最终统一颜色的初始村庄。关键规则是:一个村庄只能说服相邻村庄,当且仅当它的支持者数量不少于目标村庄的支持者数量。
核心思路
-
问题转化 将问题看作:从最终状态反向推导,哪些初始颜色可能通过合法的说服过程统一全岛。
-
关键观察 如果一个连通分量可以"吞并"相邻的连通分量,那么整个分量可以统一颜色
按村庄人口从小到大处理,保证处理顺序的合理性
- 算法流程 步骤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); } 从最大人口村庄开始传播,标记所有可能统一全岛的颜色。
算法复杂度 排序:
并查集操作:
启发式合并:
总体:
样例验证 样例1:村庄人口 [2,2,4,3]
按人口排序:1(2), 2(2), 4(3), 3(4)
处理过程:
村庄1:合并相邻小人口村庄
村庄2:继续合并
村庄4:检查是否能吞并邻居
村庄3:作为最大人口,开始传播标记
输出:1110(只有村庄4不能统一全岛)
样例2:类似处理,输出1110
这种方法巧妙地利用离线处理+并查集+贪心,高效解决了颜色统一的可达性问题。
-
- 1
信息
- ID
- 3545
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者