题目链接

给出 \(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]梦幻布丁(链表 + 启发式合并)的更多相关文章

  1. 洛谷P3201 [HNOI2009]梦幻布丁 [链表,启发式合并]

    题目传送门 梦幻布丁 题目描述 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. 输入输 ...

  2. BZOJ 1483: [HNOI2009]梦幻布丁( 链表 + 启发式合并 )

    把相同颜色的串成一个链表, 然后每次A操作就启发式合并, 然后计算对答案的影响. ----------------------------------------------------------- ...

  3. 【BZOJ1483】[HNOI2009]梦幻布丁 链表+启发式合并

    [BZOJ1483][HNOI2009]梦幻布丁 Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2 ...

  4. BZOJ 1483: [HNOI2009]梦幻布丁 [链表启发式合并]

    1483: [HNOI2009]梦幻布丁 题意:一个带颜色序列,一种颜色合并到另一种,询问有多少颜色段 一种颜色开一个链表,每次遍历小的合并到大的里,顺带维护答案 等等,合并方向有规定? 令col[x ...

  5. 洛谷 P3201 [HNOI2009]梦幻布丁(启发式合并)

    题面 luogu 题解 什么是启发式合并? 小的合并到大的上面 复杂度\(O(nlogn)\) 这题颜色的修改,即是两个序列的合并 考虑记录每个序列的\(size\) 小的合并到大的 存序列用链表 但 ...

  6. bzoj 1483: [HNOI2009]梦幻布丁 (链表启发式合并)

    Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色. 例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. Input ...

  7. 洛谷P3201 [HNOI2009]梦幻布丁

    题目描述 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. 输入输出格式 输入格式: 第 ...

  8. bzoj1483: [HNOI2009]梦幻布丁(链表+启发式合并)

    题目大意:一个序列,两种操作. ①把其中的一种数修改成另一种数 ②询问有多少段不同的数如1 2 2 1为3段(1 / 2 2 / 1). 昨晚的BC的C题和这题很类似,于是现学现写居然过了十分开心. ...

  9. 洛谷 3201 [HNOI2009]梦幻布丁 解题报告

    3201 [HNOI2009]梦幻布丁 题目描述 \(N\)个布丁摆成一行,进行\(M\)次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为\(1,2,2 ...

随机推荐

  1. Mysql报错型注入总结

    Mysql注入虽然是老生常谈的问题,但是工作中更多的是使用sqlmap等工具进行注入测试的,原理方面还是不是很清楚,所以这段时间主要是自己搭建环境在学手工注入,简单的将自己的学习做一个总结和记录.在常 ...

  2. killall命令详解

    基础命令学习目录首页 原文链接:https://blog.csdn.net/tanga842428/article/details/52474250 Linux系统中的killall命令用于杀死指定名 ...

  3. 关于React面试题汇总

    1.redux中间件 中间件提供第三方插件的模式,自定义拦截 action -> reducer 的过程.变为 action -> middlewares -> reducer .这 ...

  4. Python之并发编程-协程

    目录 一.介绍 二. yield.greenlet.gevent介绍 1.yield 2.greenlet 3.gevent 一.介绍 协程:是单线程下的并发,又称微线程,纤程.英文名Coroutin ...

  5. js为一个对象Object添加一个新的属性和值

    1, var obj = {}; //或者 var obj=new Object(); var key = "name"; var value = "张三丰" ...

  6. 2-Fourth Scrum Meeting20151204

    任务安排 闫昊: 今日完成:设计本地数据库. 明日任务:请假.(最近代码写得多……很累……) 唐彬: 今日完成:ios客户端代码的了解. 明日任务:ios客户端代码的深度学习. 史烨轩: 今日完成: ...

  7. MySQL课堂练习 20162315

    练习内容 1.参考教材相关代码,提交能连接到world的截图(有学号水印) 2.查询world数据库,获得人口超过500万的所有城市的列表. 3.查询world数据库,获得New Jersey州所有城 ...

  8. Chapter 9 软件实现

    软件实现包括代码设计.设计审查.代码编写.代码走查.代码编译和单元测试等活动.程序设计语言有很多,从机器语言到高级语言一直发展.软件编码需要遵循一些规范,JAVA代码有适当的空行,代码行及行内空格.分 ...

  9. ubuntu16.04+matlab r2015b VideoReader报错

    读取.mp4出错 需要安装gstreamer0.10-ffmpeg ` sudo add-apt-repository ppa:mc3man/gstffmpeg-keep sudo apt-get u ...

  10. Mac OS10.10 openfire无法启动问题

    1.我用的Java版本是Version 8 Update 51,验证方法可到这个网址下去验证http://www.java.com/zh_CN/download/installed.jsp 2.ope ...