[HNOI2009] 梦幻布丁
[HNOI2009] 梦幻布丁
题目描述
个布丁摆成一行,进行 次操作。每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色。
例如,颜色分别为 的四个布丁一共有 段颜色.
输入格式
第一行是两个整数,分别表示布丁个数 和操作次数 。
第二行有 个整数,第 个整数表示第 个布丁的颜色 。
接下来 行,每行描述一次操作。每行首先有一个整数 表示操作类型:
- 若 ,则后有两个整数 ,表示将颜色 的布丁全部变成颜色 。
- 若 ,则表示一次询问。
输出格式
对于每次询问,输出一行一个整数表示答案。
样例 #1
样例输入 #1
4 3
1 2 2 1
2
1 2 1
2
样例输出 #1
3
1
提示
样例 1 解释
初始时布丁颜色依次为 ,三段颜色分别为 。
一次操作后,布丁的颜色变为 ,只有 一段颜色。
数据规模与约定
对于全部的测试点,保证 ,。
提示
请注意,不保证颜色的编号不大于 ,也不保证 , 不是颜色的编号上限。
解题思路
容易想到的暴力做法是,用 std::vector
维护各个颜色的下标有那些,对于询问的 和 ,把颜色是 的下标 都改成 ,并将这些下标都存到颜色是 的 std::vector
中,同时清空颜色是 的 std::vector
,最后枚举数组 统计颜色段即可。
可以发现随着询问的增加,答案会逐渐变小,这是因为每次将颜色 修改成 ,颜色 的下标会增多,颜色 的下标清零,意味着颜色段只可能变少,不会变多。为此我们只关心当颜色是 的下标 变成颜色 时,是否会减少颜色段,即如果 , 时,颜色段就会减少。
这时就可以用启发式合并了,启发式合并的概念就是如果要合并两个集合的元素,那么应该把元素少的集合合并到元素多的集合,这样可以保证合并次数为 的级别。考虑每个元素对合并次数的贡献是多少,由于该元素只会合并到元素数量比它大的集合中,因此合并后该元素所在集合的大小至少为原来集合的两倍,假设一共有 个元素,那么这个元素最多能合并 次,因此所有元素的合并次数即总共的合并次数就是 级别。
在这题中我们应该把颜色 和 中下标数量少的合并到另外一个中,如果颜色 的 std::vector
小于颜色 的 std::vector
直接合并即可,同时把颜色是 的 修改成 。否则我们应该把颜色 的下标合并到颜色 中,这样做的话要把颜色是 的 修改成 ,这样做是没问题的,并不会影响颜色段的数量,但问题是如果下次询问的颜色是 就会出错,因为此时 中没有颜色 ,都用 来表示了。为此我们可以维护一个数组 , 表示颜色 实际上用 来表示。所以如果遇到颜色 的 std::vector
大于颜色 的 std::vector
的情况,我们应该让颜色 用下标少的颜色 来表示,为此只需交换 和 ,然后把颜色是 的下标合并到颜色 中即可,同时把颜色是 的 修改成 。
AC 代码如下,时间复杂度为 :
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10, M = 1e6 + 10;
int a[N];
vector<int> p[M];
int c[M];
int main() {
int n, m;
scanf("%d %d", &n, &m);
int ret = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", a + i);
c[a[i]] = a[i];
p[a[i]].push_back(i);
if (a[i] != a[i - 1]) ret++;
}
while (m--) {
int op;
scanf("%d", &op);
if (op == 1) {
int x, y;
scanf("%d %d", &x, &y);
if (x == y) continue;
if (p[c[x]].size() > p[c[y]].size()) swap(c[x], c[y]);
for (auto &i : p[c[x]]) {
if (a[i - 1] == c[y]) ret--;
if (a[i + 1] == c[y]) ret--;
}
for (auto &i : p[c[x]]) {
a[i] = c[y];
p[c[y]].push_back(i);
}
p[c[x]].clear();
}
else {
printf("%d\n", ret);
}
}
return 0;
}
参考资料
数据结构学习笔记(8) 启发式合并:https://zhuanlan.zhihu.com/p/560661911
题解 P3201 【[HNOI2009]梦幻布丁】:https://siyuan.blog.luogu.org/solution-p3201
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17891269.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效