洛谷 P3201 [HNOI2009] 梦幻布丁
洛谷 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] 梦幻布丁的更多相关文章
- 洛谷P3201 [HNOI2009]梦幻布丁 [链表,启发式合并]
题目传送门 梦幻布丁 题目描述 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. 输入输 ...
- 洛谷P3201 [HNOI2009]梦幻布丁(链表 + 启发式合并)
题目链接 给出 \(n\) 个布丁,每个补丁都有其颜色.现在有 \(m\) 次操作,每次操作将第 \(x_i\) 种颜色全部变为第 \(y_i\) 种颜色. 操作中可能会插入询问,回答目前总共有多少段 ...
- 洛谷P3201 [HNOI2009]梦幻布丁
题目描述 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. 输入输出格式 输入格式: 第 ...
- 洛谷 P3201 [HNOI2009]梦幻布丁(启发式合并)
题面 luogu 题解 什么是启发式合并? 小的合并到大的上面 复杂度\(O(nlogn)\) 这题颜色的修改,即是两个序列的合并 考虑记录每个序列的\(size\) 小的合并到大的 存序列用链表 但 ...
- 洛谷 3201 [HNOI2009]梦幻布丁 解题报告
3201 [HNOI2009]梦幻布丁 题目描述 \(N\)个布丁摆成一行,进行\(M\)次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为\(1,2,2 ...
- P3201 [HNOI2009]梦幻布丁
题目描述 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. 输入输出格式 输入格式: 第 ...
- luogu P3201 [HNOI2009]梦幻布丁
传送门 先考虑暴力,显然每次是把一个位置集合和另一个集合合并,同时维护答案,合并的过程中如果两个集合每有一对元素相邻,答案就减1 优化暴力的话,说到合并,怎么能不想起启发式合并呢?每次把一个大小小的集 ...
- bzoj 1483 [HNOI2009]梦幻布丁(链表+启发式合并)
1483: [HNOI2009]梦幻布丁 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1818 Solved: 761[Submit][Status ...
- BZOJ 1483: [HNOI2009]梦幻布丁( 链表 + 启发式合并 )
把相同颜色的串成一个链表, 然后每次A操作就启发式合并, 然后计算对答案的影响. ----------------------------------------------------------- ...
- BZOJ 1483: [HNOI2009]梦幻布丁 [链表启发式合并]
1483: [HNOI2009]梦幻布丁 题意:一个带颜色序列,一种颜色合并到另一种,询问有多少颜色段 一种颜色开一个链表,每次遍历小的合并到大的里,顺带维护答案 等等,合并方向有规定? 令col[x ...
随机推荐
- 在 Hugging Face 上部署语音转语音模型
介绍 S2S (语音到语音) 是 Hugging Face 社区内存在的一个令人兴奋的新项目,它结合了多种先进的模型,创造出几乎天衣无缝的体验: 你输入语音,系统会用合成的声音进行回复. 该项目利用 ...
- 网络虚拟存储 Iscsi实现方案
网络虚拟存储,通过Iscsi协议可以实现本地挂载磁盘,扩展本机设备存储. Iscsi有以下实现方案,简单介绍下: 1.Powershell 脚本 PowerShell 提供了一些 cmdlet,比如 ...
- PDF转换:从Word到Excel
一.引言 在数字化的浪潮中,PDF文件格式以其稳定性和兼容性成为了信息交流的宠儿.然而,当我们需要编辑这些PDF文件时,往往会遇到各种难题.今天,我要和大家分享的,是如何将PDF文件轻松转换成Word ...
- C++基础学习--随记
博客地址:https://www.cnblogs.com/zylyehuo/ 参考"C++基础与深度解析" 一.预备知识 // c++常用工具 /usr/bin/time //查看 ...
- 堆排序(标准版)(NB)
博客地址:https://www.cnblogs.com/zylyehuo/ # _*_coding:utf-8_*_ import random def sift(li, low, high): # ...
- 什么是集群&集群的分类
集群(Cluster) 计算机集群简称集群,是一种计算机系统,它通过一组松散集成的计算机软件(和/或)硬件连接起来高度紧密地协作完成计算工作.在某种意义上,他们可以被看作是一台计算机.集群系统中 ...
- 使用AOP技术实现接口验签
一.背景 在给第三方提供接口时,我们需要对接口进行验签.具体来说,当外部系统调用我们的接口时,请求中需要携带一个签名,我们接收到请求后,会解析数据并校验签名是否正确,以确保请求的合法性和安全性. 为了 ...
- java学习-4-核心类:字符串
实际上字符串String内部是通过一个char[]数组表示的.因此 String s = new String(new char[] {'h','e','l','l','o'}; 和 String s ...
- python的typer写cli脚本如此简单
# typer_demo.py import typer from pathlib import Path from typing import Optional from typing_extens ...
- CH9121替换注意事项
CH9121A 基于前版CH9121(无后缀字母)升级,引脚基本兼容,替换时需调整外围电路. 升级内容: 精简供电方式由3.3&1.8v双电源供电改为3.3v单电源供电: I/O 口支持3.3 ...