2154. 梦幻布丁

题目链接

2154. 梦幻布丁

题目描述

n 个布丁摆成一行,进行 m 次操作。每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色。

例如,颜色分别为 1,2,2,1 的四个布丁一共有 3 段颜色.

输入格式

第一行是两个整数,分别表示布丁个数 n 和操作次数 m
第二行有 n 个整数,第 i 个整数表示第 i 个布丁的颜色 ai
接下来 m 行,每行描述一次操作。每行首先有一个整数 op 表示操作类型:

  • op=1,则后有两个整数 x,y,表示将颜色 x 的布丁全部变成颜色 y
  • op=2,则表示一次询问。

输出格式

对于每次询问,输出一行一个整数表示答案。

样例 #1

样例输入 #1

4 3 1 2 2 1 2 1 2 1 2

样例输出 #1

3 1

提示

样例 1 解释

初始时布丁颜色依次为 1,2,2,1,三段颜色分别为 [1,1],[2,3],[4,4]
一次操作后,布丁的颜色变为 1,1,1,1,只有 [1,4] 一段颜色。

数据规模与约定

对于全部的测试点,保证 1n,m1051ai,x,y106

提示

请注意,不保证颜色的编号不大于 n,也不保证 xym 不是颜色的编号上限。

解题思路

启发式合并

首先证明启发式复杂度:给定 m 个集合,共 n 个元素。要将集合合并为一个集合,考虑每个数的贡献,假设合并一个数的复杂度为 O(op),启发式合并每次将大小较小的那个集合合并到大小更大的那个集合,设大小更小的那个集合大小为 x,则合并后的集合大小至少为 2×x
,则每个数的操作次数至多为 logn 次即可把整个元素合并在一起,故整体时间复杂度为 O(nlogn)

本题要求解颜色块的数量,可将所有颜色所在的编号用单链表表示,当要求 x 变为 y 时,采取启发式合并,如果 x 集合大小小于 y 集合大小,则可以直接遍历 x 颜色集合所有位置,更新答案,并将 x 表示的链表接在 y 上面, x  y 可以设定一个方向数组,即将所有对颜色的操作时即先用方向数组转换为对应的颜色编号,初始时,每种颜色指向初始颜色编号,一旦出现 x 集合大小不小于 y 集合大小的情况,而对于将 x 变为 y 与将 y 变为 x,对答案的贡献一样,即求解的方式一样,故直接交换方向数组即可

  • 时间复杂度:O(nlogn)

代码

// Problem: 梦幻布丁 // Contest: AcWing // URL: https://www.acwing.com/problem/content/2156/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=1e5+5,M=1e6+5; int n,m,color[N],h[M],ne[N],e[N],sz[M],cnt,res,mp[M]; void add(int a,int b) { e[cnt]=b,ne[cnt]=h[a],h[a]=cnt++; } void merge(int &x,int &y) { if(sz[x]>sz[y])swap(x,y); for(int i=h[x];~i;i=ne[i]) { int j=e[i]; res-=(color[j-1]==y)+(color[j+1]==y); } for(int i=h[x];~i;i=ne[i]) { int j=e[i]; color[j]=y; if(ne[i]==-1) { ne[i]=h[y],h[y]=h[x]; break; } } sz[y]+=sz[x],sz[x]=0,h[x]=-1; } int main() { scanf("%d%d",&n,&m); memset(h,-1,sizeof h); for(int i=1;i<=n;i++) { scanf("%d",&color[i]); add(color[i],i); sz[color[i]]++; res+=color[i]!=color[i-1]; } for(int i=0;i<M;i++)mp[i]=i; while(m--) { int op,x,y; scanf("%d",&op); if(op==2)printf("%d\n",res); else { scanf("%d%d",&x,&y); if(x!=y)merge(mp[x],mp[y]); } } return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16484483.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示