洛谷P3201 [HNOI2009]梦幻布丁(链表 + 启发式合并)
给出 \(n\) 个布丁,每个补丁都有其颜色。现在有 \(m\) 次操作,每次操作将第 \(x_i\) 种颜色全部变为第 \(y_i\) 种颜色。
操作中可能会插入询问,回答目前总共有多少段颜色。
$1 \leq n,m \leq 10^5 $
考虑稍微暴力点的做法,每次暴力修改颜色,然后如果对于当前的颜色,找到他们所有的位置,假设其中一个为 \(p\) ,那么通过判断 \(p-1,p+1\)位置的颜色是否为 \(y_i\) 即可。
如果这样做,就需要链表来寻找位置。但是这样还是要超时,复杂度可能为 \(O(n^2)\)。
在这里,可以使用启发式合并,即是每次把小范围并到大范围上去,由于小范围中的数每被并一次,范围中的数至少增大一倍,也就是说每个数最后被并 \(\log(n)\) 次,总的复杂度为 \(O(nlogn)\) 的。
但目前考虑到这里还不足以解决问题,因为题目给出的 “\(x_i,y_i\)”不一定满足 \(x_i<y_i\)。
这里的解决方法就是还是将小范围并到大范围,这里中间的判断操作是不影响的,唯一有变化的就是最终的颜色,我们用一个数组来记录一下最终的颜色就可以了。\(f[i]=j\) 的含义就为 \(i\) 颜色目前为颜色为 \(j\) 的链,然后每次找 \(f[i]\) 即可。数组可以解决很多事情~
具体见代码吧:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
int n, m, ans;
int col[N], first[N], nxt[N], head[N], sz[N], f[N];
int now_c[N] ;
void merge(int x, int y) {
for(int i = head[x]; i; i = nxt[i])
ans -= (col[i - 1] == y) + (col[i + 1] == y);
for(int i = head[x]; i; i = nxt[i]) col[i] = y;
nxt[first[x]] = head[y];
head[y] = head[x];
sz[y] += sz[x]; sz[x] = 0; head[x] = 0;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0) ;
cin >> n >> m;
for(int i = 1; i <= n; i++) {
cin >> col[i] ;
f[col[i]] = col[i] ;
if(col[i] != col[i - 1]) ans++ ;
if(!head[col[i]]) first[col[i]] = i;
++sz[col[i]]; nxt[i] = head[col[i]]; head[col[i]] = i ;
}
for(int i = 1; i <= m; i++) {
int op, x, y;
cin >> op;
if(op == 2) cout << ans << '\n';
else {
cin >> x >> y ;
if(sz[f[x]] > sz[f[y]]) swap(f[x], f[y]) ;
if(sz[f[x]] == 0) continue ;
merge(f[x], f[y]) ;
}
}
return 0;
}
洛谷P3201 [HNOI2009]梦幻布丁(链表 + 启发式合并)的更多相关文章
- 洛谷P3201 [HNOI2009]梦幻布丁 [链表,启发式合并]
题目传送门 梦幻布丁 题目描述 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. 输入输 ...
- BZOJ 1483: [HNOI2009]梦幻布丁( 链表 + 启发式合并 )
把相同颜色的串成一个链表, 然后每次A操作就启发式合并, 然后计算对答案的影响. ----------------------------------------------------------- ...
- 【BZOJ1483】[HNOI2009]梦幻布丁 链表+启发式合并
[BZOJ1483][HNOI2009]梦幻布丁 Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2 ...
- BZOJ 1483: [HNOI2009]梦幻布丁 [链表启发式合并]
1483: [HNOI2009]梦幻布丁 题意:一个带颜色序列,一种颜色合并到另一种,询问有多少颜色段 一种颜色开一个链表,每次遍历小的合并到大的里,顺带维护答案 等等,合并方向有规定? 令col[x ...
- 洛谷 P3201 [HNOI2009]梦幻布丁(启发式合并)
题面 luogu 题解 什么是启发式合并? 小的合并到大的上面 复杂度\(O(nlogn)\) 这题颜色的修改,即是两个序列的合并 考虑记录每个序列的\(size\) 小的合并到大的 存序列用链表 但 ...
- bzoj 1483: [HNOI2009]梦幻布丁 (链表启发式合并)
Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色. 例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. Input ...
- 洛谷P3201 [HNOI2009]梦幻布丁
题目描述 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. 输入输出格式 输入格式: 第 ...
- bzoj1483: [HNOI2009]梦幻布丁(链表+启发式合并)
题目大意:一个序列,两种操作. ①把其中的一种数修改成另一种数 ②询问有多少段不同的数如1 2 2 1为3段(1 / 2 2 / 1). 昨晚的BC的C题和这题很类似,于是现学现写居然过了十分开心. ...
- 洛谷 3201 [HNOI2009]梦幻布丁 解题报告
3201 [HNOI2009]梦幻布丁 题目描述 \(N\)个布丁摆成一行,进行\(M\)次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为\(1,2,2 ...
随机推荐
- Mac 终端快捷键
ctrl+A 跳转到行开头 ctrl+E 跳转到行结尾 ctrl+U 清空当前行 Command+K 清屏 Command+→多终端页面跳转 ...
- React Native (0.57)开发环境搭建(注意:Node不要随便更新到最新版,更新完后莫名其妙的问题一大堆)
搭建开发环境 一.安装依赖 必须安装的依赖有:Node.Watchman 和 React Native 命令行工具以及 Xcode. 1.首先安装 Homebrew 2.安装 Node, Watchm ...
- 在虚拟机下安装Ubuntu
目录: 1.安装虚拟机 2.在虚拟下安装Ubuntu 本文将按照目录分两步来讲一下在虚拟机下安装Ubuntu.第一步是安装虚拟机,第二步是在虚拟机下安装Ubuntu. 安装虚拟机 下载虚拟机链接以及激 ...
- c# combobox向上展开
1.问题情境:实际中的下拉框默认向下扩展,如果屏幕下方空间不足,会向上扩展. 向下扩展情况下,有时候会超出form窗体. 2.解决办法: 寻找相关属性无果. 退而求其次,重画item的框.发现Draw ...
- 关于Target=" "的一些属性
总结目前所知的Target=""的几个属性,对其它博客进行整理和归纳. Target="_blank":浏览器总在一个新打开.未命名的窗口中载入目标文档. 说通 ...
- 第一个spring冲刺总结
讨论成员:罗凯旋.罗林杰.吴伟锋.黎文衷 第一阶段总体是做到了运算的功能,只是一些基本的功能实现,包括APP进入动画,以及界面的基本效果设计,还有核心算法已经实现(可以计算括号 乘除法等等)“: 燃尽 ...
- 灵悟礼品网上专卖店Sprint计划
一.现状 小组成员初步了解了所做项目的大致内容,需要时间一步一步分析和规划. 二.部分需求索引卡 第一个阶段没有具体功能的实现,只是先把所要做的项目思路理清,并把相应的数据库建立好. 三.任务认领 产 ...
- 【图论】POJ-3723 最大生成树
一.题目 Description Windy has a country, and he wants to build an army to protect his country. He has p ...
- 项目冲刺Beta第一篇博客
Beta版本冲刺计划安排 1.当天站立式会议照片: 2.工作分工: 团队成员 分工 张洪滨060 排行榜界面美化 陈敬轩059 注册成功界面美化 黄兴067 登录界面美化 林国梽068 答题界 ...
- 约跑APP测试
项目名:约跑APP 用户需求规格说明书URL:http://www.cnblogs.com/liquan/p/6071804.html 组长博客URL:http://www.cnblogs.com/l ...