洛谷 P3201 [HNOI2009] 梦幻布丁

祭我AC的第十道紫题。

听了一下午的

才调出来。

题意分析

洛谷传送门

给一个序列a,有两种操作——

1 x y将序列中所有x全部变成y

2查询当前序列有多少段。

\(1\le n,m\le 10^5,1\le a_i,x,y\le 10^6\)。

Solution

考虑每修改一个位置带来的贡献(亦或者说是影响?)。我们每将一个\(a_i=x\)修改为了\(y\),那么如果\(a_{i-1} =y\)或\(a_{i+1}=y\)都会使段数\(+1\)。

但是这样虽然简化的操作\(2\),但是\(1\)还是需要\(O(n)\)的时间来维护。

但是如果我们修改颜色时,将数量少的那一种颜色修改为数量多的那一种,这样修改次数就大大减少了。这种合并方案属于启发式合并

至于用什么方式来合并。思来思去,还是用链表解决最优。(当然什么set,vector,线段树合并都行)。

设链表的值为\(f_i\),大小为\(size_i\),起点为\(head_i\),指针为\(next_i\)。

开始时,先将同一种颜色放到一个链表中,并计算原序列有多少段。

读入\(x,y\)并比较链表大小(注意交换的是\(f_x,f_y\),相当于交换了两个链表)。

统计贡献之后再修改小链表的颜色,把小链表塞到打链表的前面,更新大链表的\(size,head\)。

清空小链表的\(head,size\)。

Code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<limits.h>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#ifdef TH
#define debug printf("Now is %d\n",__LINE__);
#else
#define debug
#endif
using namespace std; template<class T>inline void read(T&x)
{
char ch=getchar();
int fu;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') fu=-1,ch=getchar();
x=ch-'0';ch=getchar();
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
x*=fu;
}
inline int read()
{
int x=0,fu=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') fu=-1,ch=getchar();
x=ch-'0';ch=getchar();
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*fu;
}
int G[55];
template<class T>inline void write(T x)
{
int g=0;
if(x<0) x=-x,putchar('-');
do{G[++g]=x%10;x/=10;}while(x);
for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n');
}
#define N 100010
int n,m;
int a[N];
int ans;
int f[N*10],sze[N*10];
int head[N*10],nxt[N*10];
int main()
{
// freopen("P3201.in","r",stdin);
// freopen("P3201.out","w",stdout);
n=read();
m=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
f[a[i]]=a[i];
sze[a[i]]++;
nxt[i]=head[a[i]];
head[a[i]]=i;
if(a[i]!=a[i-1]) ans++;
}
int op,x,y;
while(m--)
{
op=read();
if(op==1)
{
x=read();
y=read();
if(x==y) continue;
if(sze[f[x]]>sze[f[y]]) swap(f[x],f[y]);//Æô·¢Ê½ºÏ²¢
x=f[x];
y=f[y];
for(int i=head[x];i;i=nxt[i])
{
if(a[i+1]==y) ans--;
if(a[i-1]==y) ans--;
}
int j=0;
for(int i=head[x];i;i=nxt[i]) a[j=i]=y;
if(head[x]) nxt[j]=head[y],head[y]=head[x];
sze[y]+=sze[x];
sze[x]=0;
head[x]=0;
}
else write(ans);
// for(int i=1;i<=n;i++) cout<<a[i]<<" ";
// cout<<endl;
}
return 0;
}

Attention

注意特判\(x=y\)。

这个合并我实在是不会用vector,vector貌似不能\(O(1)\)合并……

洛谷 P3201 [HNOI2009] 梦幻布丁的更多相关文章

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

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

  2. 洛谷P3201 [HNOI2009]梦幻布丁(链表 + 启发式合并)

    题目链接 给出 \(n\) 个布丁,每个补丁都有其颜色.现在有 \(m\) 次操作,每次操作将第 \(x_i\) 种颜色全部变为第 \(y_i\) 种颜色. 操作中可能会插入询问,回答目前总共有多少段 ...

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

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

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

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

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

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

  6. P3201 [HNOI2009]梦幻布丁

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

  7. luogu P3201 [HNOI2009]梦幻布丁

    传送门 先考虑暴力,显然每次是把一个位置集合和另一个集合合并,同时维护答案,合并的过程中如果两个集合每有一对元素相邻,答案就减1 优化暴力的话,说到合并,怎么能不想起启发式合并呢?每次把一个大小小的集 ...

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

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

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

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

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

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

随机推荐

  1. Paimon merge into 实现原理

    语法 MERGE INTO target USING source ON source.a = target.a WHEN MATCHED THEN UPDATE SET a = source.a, ...

  2. sudo: unable to resolve host xxxx: Name or service not known

    前言 在 Linux 环境中,我使用 sudo 执行命令,发生报错:sudo: unable to resolve host xxxx: Name or service not known 解决 这个 ...

  3. Dockerfile 语法与常用命令

    转发请注明出处: 一.Dockerfile 核心语法规则 指令大写:所有指令必须大写(如 FROM, RUN) 顺序执行:指令按顺序从上到下执行 分层构建:每条指令生成一个镜像层,修改上层不会影响下层 ...

  4. Docker管理面板系列——Portainer

    一.介绍 Portainer是个轻量级的Docker管理面板,和Rancher这种重量级选手没法比,Portainer倾向于单机的管理(后来发现能够添加多个单机节点切换着管理),当然,在Docker搞 ...

  5. 团队小规模本地大模型服务平台搭建 - Ubuntu

    实现目标和考虑因素 部署一个支持多用户同时使用.多模型运行的离线局域网大模型服务器 需要考虑以下几个关键因素: 大模型的加载和管理.使用一个基础大模型,根据实战需要创建多个专用模型,模型管理方便可靠. ...

  6. emlog pro 文章编辑器(editor.md)的快捷键

    这里是一张图片,上面显示目前 emlog pro 编辑器所有**有效**的快捷键 (注意,是有效的快捷键,与 editor.md 官方公布的有出入,有些在系统是不可用的),对于长期使用emlog写作的 ...

  7. Next.js中间件权限绕过漏洞分析(CVE-2025-29927)

    本文代码版本为next.js-15.2.2 本篇文章首发在先知社区:https://xz.aliyun.com/news/17403 一.漏洞概述 CVE-2025-29927是Next.js框架中存 ...

  8. Random和猜数字小游戏

    1.Random:使用方式和Scanner一样 Random用于生成随机数,括号里的10就是指在10以内随机生成一个数(0~9) Random生成的随机数都是从0开头 . 提问:那该如何让Random ...

  9. 聊聊AI Agent与AI 数字分身

    提供AI应用咨询+陪跑服务,有需要回复1 Manus爆火后,网上出现了很多AI热门名词,比如Agent.AI分身,并且有一张技术架构实现图: 怎么说呢,也许这张图是对的,但就我这边实际的项目实践情况以 ...

  10. 什么是 MCP,以及你为什么该关注它

    MCP 现在真的火起来了.现在已经有成千上万个 MCP "服务器",而且虽然是 Anthropic 发明的,就在几天前 OpenAI 也采纳了它.服务器就像 AI 的 " ...