(画师当然是武内崇啦)

Description

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

Input

第一行给出N,M表示布丁的个数和好友的操作次数. 第二行N个数A1,A2…An表示第i个布丁的颜色从第三行起有M行,对于每个操作,若第一个数字是1表示要对颜色进行改变,其后的两个整数X,Y表示将所有颜色为X的变为Y,X可能等于Y. 若第一个数字为2表示要进行询问当前有多少段颜色,这时你应该输出一个整数. 0

Output

针对第二类操作即询问,依次输出当前有多少段颜色.

Sample Input

4 3

1 2 2 1

2

1 2 1

2

Sample Output

3

1

最近在复习数据结构,本来打算找一道平衡树的题来做,在黄学长的博客里看到这道题。结果发现和平衡树其实没有关系。。。

看到这个题的第一想法是暴力:每次o(n)修改或查询

然而o(n^2)肯定会爆(虽然题目不给范围神坑)。我们希望能够通过某些手段来降log。首先是想到线段树,因为线段树可以解决区间内连续色段,但是我们发现这道题是针对整个序列而言,且修改无法用线段树优化。

那怎么办呢?我们发现这道题是将所有颜色为x的改为y,总共有效的修改数量是初始时的颜色种数(最多n)。其实这相当于将颜色x与颜色y合并,且之后不会再拆开。所以说这就是合并的问题啦~(废话了这么久。。)

但是该如何合并呢?我们将同一种颜色的布丁用链表连起来,合并的时候是o(1)的。但是对于合并时ans的更新是o(n)的(对于每一个都判断修改后是否与左右连接)。总的来说,就是每次合并时的复杂度“被修改的颜色的布丁个数”。

这个是可以优化的,就是用启发式合并(把小的往大的合并)。这样就是o(nlogn)的了。证明就搬一下黄学长的;

1:每次O(N)

2:每次合并后,队列长度一定大于等于原来短的长度的两倍。

这样相当于每次合并都会让短的长度扩大一倍以上,

最多扩大logN次,所以总复杂度O(NlogN),每次O(logN)。

但是由于为了启发式合并,我们改变了合并方向。需要用一个f[i]数组来存 调用i颜色时真正用到的颜色。

下面谈谈链表:

我以前一直都不清楚链表到底是个什么货。现在好像是明白了:

有两种链表:

1、对于每个点,有一个pre(前继)和nxt(后继)。这相当于双向链表

2、记录一个链表的开头head,对每个点记录一个nxt(下一个)。这相当于是单向链表

这道题需要访问链表的全部元素,所以用第二种链表。

(其实之前接触过这链表很多次,但一直不知道这就是链表)

放代码啦:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int N=1000000+5; int n,m,c[N],siz[N],f[N],ans=0;
int head[N],nxt[N],st[N]; void solve(int a,int b){
for(int i=head[a];i;i=nxt[i]){
if(c[i+1]==b) ans--;
if(c[i-1]==b) ans--;
}
for(int i=head[a];i;i=nxt[i]) c[i]=b;
/*这是两种不同的合并方式*/
// nxt[st[a]]=head[b];head[b]=head[a];
nxt[st[b]]=head[a];
// head[a]=0,st[a]=0;
st[b]=st[a];
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&c[i]);
siz[c[i]]++,f[c[i]]=c[i];
if(c[i]!=c[i-1]) ans++;
if(!head[c[i]]) st[c[i]]=i;
nxt[i]=head[c[i]],head[c[i]]=i;
}
int opt,x,y;
while(m--){
scanf("%d",&opt);
if(opt==2) printf("%d\n",ans);
else{
scanf("%d%d",&x,&y);
if(x==y) continue;//
if(siz[f[x]]==0) continue;
if(siz[f[x]]>siz[f[y]]) swap(f[x],f[y]);
if(siz[f[x]]==0) continue;
siz[f[x]]+=siz[f[y]],siz[f[x]]=0;//+=
solve(f[x],f[y]);
}
}
return 0;
}

【bzoj1486】【[HNOI2009]梦幻布丁】启发式链表合并(详解)的更多相关文章

  1. [BZOJ 1483] [HNOI2009] 梦幻布丁 (线段树合并)

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

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

    1483: [HNOI2009]梦幻布丁 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1818  Solved: 761[Submit][Status ...

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

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

  4. bzoj 1483: [HNOI2009]梦幻布丁 启发式合并vector

    1483: [HNOI2009]梦幻布丁 Time Limit: 10 Sec  Memory Limit: 64 MB[Submit][Status][Discuss] Description N个 ...

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

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

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

    http://www.lydsy.com/JudgeOnline/problem.php?id=1483 题意:中文. 思路:对于每一种颜色,用一个链表串起来,一开始保存一个答案,后面颜色替换的时候再 ...

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

    洛谷传送门 开始一个O(n^2)思路,每次每句要改变颜色的点,改变完颜色后重新计算颜色的段数,显然拉闸. 然后呢..然后就不会了. 看了别人博客,才知道有个叫做启发式合并的东西,就是把小的合并到大的上 ...

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

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

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

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

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

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

随机推荐

  1. java注解(Annotation)的简单介绍

    注解你可以理解为一个特殊的类,或者接口其自定义个格式形如 public @interface 注解名(){ //注解的属性,特别提醒当注解的属性为value时,在对其赋值时,可以不写value,而直接 ...

  2. VC++使用CImage PNG转BMP图片透明背景处理

    PNG格式的图片是支持透明通道的,BMP格式的图片是没有透明通道的,所以当PNG格式的图片转换为BMP格式时,对于PNG图片的透明背景就需要进行特别的处理. VC++中的HBITMAP是支持透明色的, ...

  3. Join to domain powershell script

    Join to domain powershell script $username = "domain\admin" $Password = "xxxxxxxx&quo ...

  4. CSS3奇偶选择器

    .search-form td:nth-child(odd){//奇 width:100px; text-align:right;} .search-form td:nth-child(even){/ ...

  5. 转:LVS负载均衡

    1.什么是LVS? 首 先简单介绍一下LVS (Linux Virtual Server)到底是什么东西,其实它是一种集群(Cluster)技术,采用IP负载均衡技术和 基于内容请求分发技术.调度器具 ...

  6. NGINX : 如何屏蔽未被定义的虚拟主机的访问

    参考: [ how to prevent undefined server names ] nginx 的默认虚拟主机 Nginx 支持基于域名和端口的虚拟主机(virtual host), 根据获取 ...

  7. 【洛谷 P4886】 快递员 (点分治)

    这题因为一些小细节还是\(debug\)了很久...不过我第一次用脚本对拍,不亏. 先随便找一个点作为根,算出答案,即所有点对到这个点的距离和的最大值,并记录所有距离最大的点对.如果这个点在任意一个距 ...

  8. 基于iscroll实现下拉和上拉刷新

    在原生APP的开发中,有一个常见的功能,就是下拉刷新的功能,这个想必大家都是知道的,但是原生APP的开发,有一个很大的问题就是,你每次更新一些功能,就要用户重新下载一次版本,尤其是在iOS系统中,新版 ...

  9. codevs 1085

    数字游戏 2003年NOIP全国联赛普及组 时间限制: s 空间限制: KB 题目等级 : 黄金 Gold 题解 题目描述 Description 丁丁最近沉迷于一个数字游戏之中.这个游戏看似简单,但 ...

  10. Activiti 6.0 入门篇

    从Activiti网站下载Activiti UI WAR文件(或百度云) 将下载的activiti-app.war复制到Tomcat的webapps目录. 启动Tomcat 打开浏览器并转到 http ...