LG P4119 [Ynoi2018] 未来日记 Solution

news2025/6/2 23:44:11

Description

给定序列 a = ( a 1 , a 2 , ⋯   , a n ) a=(a_1,a_2,\cdots,a_n) a=(a1,a2,,an),有 m m m 个操作分两种:

  • replace ⁡ ( l , r , x , y ) \operatorname{replace}(l,r,x,y) replace(l,r,x,y):将 a l ∼ a r a_l\sim a_r alar 中的所有 x x x 替换为 y y y.
  • kth ⁡ ( l , r , k ) \operatorname{kth}(l,r,k) kth(l,r,k):求 a l ∼ a r a_l\sim a_r alar 中的第 k k k 小值.

Limitations

1 ≤ n , m , a i , x , y ≤ 1 0 5 1\le n,m,a_i,x,y\le 10^5 1n,m,ai,x,y105
1 ≤ l ≤ r ≤ n 1\le l\le r\le n 1lrn
1 s , 512 MB \textcolor{red}{1\text{s}},512\text{MB} 1s,512MB

Solution

很奇怪的操作,考虑给序列 a a a 分块.
由于要查询第 k k k 小,再给值域 [ 1 , 1 0 5 ] [1,10^5] [1,105] 分块.
预处理两个数组:

  • f i , j f_{i,j} fi,j:第 1 ∼ i 1\sim i 1i序列块中, j j j 的出现次数.
  • g i , j g_{i,j} gi,j:第 1 ∼ i 1\sim i 1i序列块中,第 j j j值域块内数的的出现次数.

并在每块挂上一个 vector 存储该块的操作,重构块时,遍历 vector 计算出 to i \textit{to}_i toi 表示 i i i 这个数值最终会变成什么,然后直接在 a a a 上修改,并把 vector 清空.

考虑修改,对于整块,我们直接把操作塞入对应块的 vector 中;对于散块,我们暴力替换.
当然 f f f g g g 也要更新,所以替换时需要记录 t i t_i ti 表示第 i i i 块内的替换次数,在所有块修改完后更新这两个数组.

接着考虑查询,我们先对每个 i i i 求出第 i i i值域块内数在 a l ∼ a r a_l\sim a_r alar 的出现次数,然后定出第 k k k 小值所在的值域块.
接着再求出数值 i i i a l ∼ a r a_l\sim a_r alar 的出现次数,再在上一步确定的值域块内找出真正的第 k k k 小值.
此时 f f f g g g 就发挥了作用,因为要求出连续整块内一个数(或一个值域块内数)的出现次数.(散块就直接暴力装桶)

至此就想完了,然而本题很毒瘤(又难写又卡常),注意以下几点:

  • 块长取 350 350 350 左右,太小会爆空间.
  • 注意区分序列块值域块.
  • x = y x=y x=y 的修改直接忽略.
  • 不要开太多 vector,要加快读快写.
  • 注意优化清空过程.

Code

5.05 KB , 6.25 s , 204.35 MB    (in   total,   C++20   with   O2) 5.05\text{KB},6.25\text{s},204.35\text{MB}\;\texttt{(in total, C++20 with O2)} 5.05KB,6.25s,204.35MB(in total, C++20 with O2)
常数很大,最大点要 0.84 s \textcolor{red}{0.84\text{s}} 0.84s.

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;

template<class T>
bool chmax(T &a, const T &b){
	if(a < b){ a = b; return true; }
	return false;
}

template<class T>
bool chmin(T &a, const T &b){
	if(a > b){ a = b; return true; }
	return false;
}

namespace fastio {}      // By pystraf
using fastio::read;
using fastio::write;

constexpr int B = 350, V = 1e5 + 10, M = (V + B - 1) / B;
using pii = pair<int, int>;

namespace pool {
	constexpr int L = 4e7 + 10;
	int P[L], *ptr = P;
	
	inline int* alloc(int n) {
		int* res = ptr;
		ptr += n;
		return res;
	}
}
using pool::alloc;

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	
	const int n = read<int>(), q = read<int>();
	const int blocks = (n + B - 1) / B;
	
	int* a = alloc(n);
	for (int i = 0; i < n; i++) a[i] = read<int>();
	
	int *bel = alloc(V), *to = alloc(V), *L = alloc(blocks), *R = alloc(blocks), *tmp = alloc(V);
	vector<int*> f(blocks), g(blocks);
	vector<vector<pii>> mdf(blocks);
	
	for (int i = 0; i < blocks; i++) f[i] = alloc(V), g[i] = alloc(M);
	
	auto init = [&]() {
		for (int i = 0; i < V; i++) {
			bel[i] = i / B;
			to[i] = i;
		}
		
		for (int i = 0; i < blocks; i++) {
			L[i] = i * B;
			R[i] = min(L[i] + B, n) - 1;
			
			if (i > 0) {
				for (int j = 0; j < V; j++) f[i][j] = f[i - 1][j];
				for (int j = 0; j < M; j++) g[i][j] = g[i - 1][j];
			}
			
			for (int j = L[i]; j <= R[i]; j++) {
				f[i][a[j]]++;
				g[i][bel[a[j]]]++;
			}
		}
	};
	
	auto refact = [&](int b) {
		vector<int> vec;
		vector<pii> & opr = mdf[b];
		reverse(opr.begin(), opr.end());
		
		for (auto & [x, y] : opr) {
			to[x] = to[y];
			vec.push_back(x);
			vec.push_back(y);
		}
		
		for (int i = L[b]; i <= R[b]; i++) a[i] = to[a[i]];
		
		for (auto x : vec) to[x] = x;
		opr.clear();
	};
	
	auto brute_replace = [&](int b, int l, int r, int x, int y) {
		refact(b);
		for (int i = l; i <= r; i++)
		    if (a[i] == x) {
		    	a[i] = y;
		    	tmp[b]++;
		    }
	};
	
	auto block_replace = [&](int b, int x, int y) {
		mdf[b].emplace_back(x, y);
		tmp[b] = f[b][x] - f[b - 1][x];
	};
	
	auto update = [&](int b, int x, int y) {
		for (int i = b; i < blocks; i++) {
			if (i > 0) tmp[i] += tmp[i - 1];
			f[i][x] -= tmp[i], f[i][y] += tmp[i];
			g[i][bel[x]] -= tmp[i], g[i][bel[y]] += tmp[i];
		}
	};
	
	auto replace = [&](int l, int r, int x, int y) {
        if (x == y) return;
		const int bl = bel[l], br = bel[r];
		for (int i = 0; i < blocks; i++) tmp[i] = 0;
		
		if (bl == br) brute_replace(bl, l, r, x, y);
		else {
			brute_replace(bl, l, R[bl], x, y);
			brute_replace(br, L[br], r, x, y);
			for (int i = bl + 1; i < br; i++) block_replace(i, x, y);
		}
		
		update(bl, x, y);
	};
	
	auto count = [&](
	        int bl, int br, int fl, int fr, 
	        int k, int sum, const vector<int>& vec
	) -> pii {
		if (fl == -1) {
			for (int i = 0; i < M; i++) tmp[i] = (bl ^ br) ? (g[br - 1][i] - g[bl][i]) : 0;
            for (auto & x : vec) tmp[bel[x]]++;
			for (int i = 0; i < M; i++) {
				sum += tmp[i];
				if (sum >= k) return pii(i, sum - tmp[i]);
			}
		}
		else {
			for (int i = fl; i <= fr; i++) tmp[i] = (bl ^ br) ? (f[br - 1][i] - f[bl][i]) : 0;
            for (auto & x : vec) tmp[x]++;
			for (int i = fl; i <= fr; i++) {
				sum += tmp[i];
				if (sum >= k) return pii(i, 0);
			}
		}
		return pii(-1, 0);
	};
	
	auto add = [&](int l, int r, vector<int>& vec) {
		for (int i = l; i <= r; i++) vec.push_back(a[i]);
	};
	
	auto kth = [&](int l, int r, int k) -> int {
		vector<int> vec;
		const int bl = bel[l], br = bel[r];
		
		if (bl == br) {
			refact(bl);
			add(l, r, vec);
			
			auto [blk, sum] = count(bl, bl, -1, -1, k, 0, vec);
			if (blk == -1) return -1;

			const int fl = blk * B, fr = min(fl + B, V) - 1;
			auto [res, _] = count(bl, bl, fl, fr, k, sum, vec);
			return res;
		}
		
		refact(bl), refact(br);
		add(l, R[bl], vec), add(L[br], r, vec);
		
		auto [blk, sum] = count(bl, br, -1, -1, k, 0, vec);
		if (blk == -1) return -1;

		const int fl = blk * B, fr = min(fl + B, V) - 1;
		auto [res, _] = count(bl, br, fl, fr, k, sum, vec);
		return res;
	};
	
	init();
	for (int i = 0, op, l, r, x, y; i < q; i++) {
		op = read<int>(), l = read<int>(), r = read<int>(), x = read<int>();
		l--, r--;
		if (op == 1) y = read<int>(), replace(l, r, x, y);
		else {
			write(kth(l, r, x));
			putchar_unlocked('\n');
		}
	}
	
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2394324.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

哈工大计统大作业-程序人生

摘 要 本项目以“程序人生-Hellos P2P”为核心&#xff0c;通过编写、预处理、编译、汇编、链接及运行一个简单的Hello程序&#xff0c;系统探讨了计算机系统中程序从代码到进程的全生命周期。实验基于Ubuntu环境&#xff0c;使用GCC工具链完成代码转换&#xff0c;分析了预处…

设计模式——装饰器设计模式(结构型)

摘要 文中主要介绍了装饰器设计模式&#xff0c;它是一种结构型设计模式&#xff0c;可在不改变原有类代码的情况下&#xff0c;动态为对象添加额外功能。文中详细阐述了装饰器模式的角色、结构、实现方式、适合场景以及实战示例等内容&#xff0c;还探讨了其与其他设计模式的…

途景VR智拍APP:开启沉浸式VR拍摄体验

在数字化时代&#xff0c;VR技术以其沉浸式的体验逐渐走进了人们的日常生活。途景VR智拍APP作为一款集看图和拍照于一体的VR软件&#xff0c;为用户带来了全新的视觉体验和便捷的拍摄方式&#xff0c;无论是专业摄影师还是普通用户&#xff0c;都能轻松上手&#xff0c;拍出令人…

Linux环境搭建MCU开发环境

操作系统版本&#xff1a; ubuntu 22.04 文本编辑器&#xff1a; vscode 开发板&#xff1a; stm32f103c8t6 调试器&#xff1a; st-link 前言 步骤一&#xff1a; 安装交叉编译工具链 步骤二&#xff1a; 创建工程目录结构 步骤三&#xff1a; 调试…

【基础算法】高精度(加、减、乘、除)

文章目录 什么是高精度1. 高精度加法解题思路代码实现 2. 高精度减法解题思路代码实现 3. 高精度乘法解题思路代码实现 4. 高精度除法 (高精度 / 低精度)解题思路代码实现 什么是高精度 我们平时使用加减乘除的时候都是直接使用 - * / 这些符号&#xff0c;前提是进行运算的数…

Windows最快速打开各项系统设置大全

目录 一、应用背景 二、设置项打开方法 2.1 方法一界面查找&#xff08;最慢&#xff09; 2.2 方法二cmd命令&#xff08;慢&#xff09; 2.3 方法三快捷键&#xff08;快&#xff09; 2.4 方法四搜索栏&#xff08;快&#xff09; 2.5 方法五任务栏&#xff08;最快&am…

嵌入式编译工具链熟悉与游戏移植

在自己的虚拟机Ubuntu系统下&#xff0c;逐步编译 mininim源码(波斯王子重制开源版&#xff09; 指令流程 sudo apt-get remove liballegro5-dev liballegro-image5-dev \liballegro-audio5-dev liballegro-acodec5-dev liballegro-dialog5-dev sudo apt-get install automak…

DeepSeek-R1-0528,官方的端午节特别献礼

DeepSeek&#xff1a;端午安康&#xff01;刻在国人骨子里的浪漫 2025 年 05 月 28 日 | DeepSeek 端午特别献礼 当粽叶飘香时&#xff0c;DeepSeek 悄然带来一份节日惊喜 版本号 DeepSeek-R1-0528 正式上线 官方赋予它的灵魂是&#xff1a; 思考更深 推理更强 用户通过官网…

001 flutter学习的注意事项及前期准备

在学习flutter之前&#xff0c;还需要进行一些初始的配置&#xff0c;然后才可以学习flutter 1.安装flutter 国内官网&#xff1a;https://flutter.cn​​​​​​ 国际官网&#xff1a;https://flutter.dev 安装完成后&#xff0c;按照官网上面的操作步骤进行配置&#xf…

CS144 - Lecture 1 记录

CS144 - Lecture 1 由于没讲义&#xff0c;全看课了&#xff0c;系统性的总结有点难&#xff0c;记一些有趣的东西吧。 数据链路和网络层的传输 我们可以看见&#xff0c;对于发送方&#xff0c;我们的数据链路层为我们的网络层提供服务&#xff0c;在经过路由的时候&#xf…

【数据结构】——二叉树--链式结构

一、实现链式结构二叉树 二叉树的链式结构&#xff0c;那么从名字上我们就知道我们这个二叉树的底层是使用链表来实现的&#xff0c;前面我们的二叉树是通过数组来实现的&#xff0c;那么在其是完全二叉树的情况下&#xff0c;此时我们使用数组来实现就会使得其空间浪费较少&a…

充电便捷,新能源汽车移动充电服务如何预约充电

随着新能源汽车的普及&#xff0c;充电便捷性成为影响用户体验的关键因素之一。传统的固定充电桩受限于地理位置和数量&#xff0c;难以完全满足用户需求&#xff0c;而移动充电服务的出现&#xff0c;为车主提供了更加灵活的补能方式。通过手机APP、小程序或在线平台&#xff…

基于 Chrome 浏览器扩展的Chroma简易图形化界面

简介 ChromaDB Manager 是基于 Chrome 浏览器扩展的一款 ChromaDB&#xff08;一个流行的向量数据库&#xff09;的数据查询工具。提供了一个用户友好的界面&#xff0c;可以直接从浏览器连接到本地 ChromaDB 实例、查看集合信息和分片数据。本工具特别适合开发人员快速查看和…

IM系统的负载均衡

1.IM场景的负载均衡 2.方案总览 SDK层想要连接一个TCP网关或者WebSocket网关的方案 SDK单地址:在SDK中写死某个网关的IP或者域名,缺点是更换地址需要重新打包SDK SDK多地址:防止某一个地址嗝屁了写上多个地址用足保持高可用 暴露接口给客户端:SDK层访问接口动态获得地址 注…

使用 Zabbix 监控 MySQL 存储空间和性能指标的完整实践指南

目录 引言 一、最终目标支持功能 二、监控方案设计 2.1 技术选型 2.2 设计思路 三、实现步骤 3.1 准备工作 3.11 创建 MySQL 监控账号 3.12 配置 .my.cnf 文件 3.2 编写统一脚本 3.3 配置 Zabbix Agent UserParameter 3.4 Zabbix 前端配置建议 四、总结 引言 MySQL …

【技能拾遗】——家庭宽带单线复用布线与配置(移动2025版)

&#x1f4d6; 前言&#xff1a;在家庭网络拓扑中&#xff0c;客厅到弱电箱只预埋了一根网线&#xff0c;由于已将广电的有线电视取消并改用IPTV。现在需要解决在客厅布置路由器和观看IPTV问题&#xff0c;这里就用到单线复用技术。 目录 &#x1f552; 1. 拓扑规划&#x1f55…

异步日志监控:FastAPI与MongoDB的高效整合之道

title: 异步日志监控:FastAPI与MongoDB的高效整合之道 date: 2025/05/27 17:49:39 updated: 2025/05/27 17:49:39 author: cmdragon excerpt: FastAPI与MongoDB整合实现日志监控系统的实战指南。首先配置MongoDB异步连接,定义日志数据模型。核心功能包括日志写入接口、聚合…

在 Android 上备份短信:保护您的对话

尽管我们的Android手机有足够的存储空间来存储无数的短信&#xff0c;但由于设备故障、意外删除或其他意外原因&#xff0c;您可能会丢失重要的对话。幸运的是&#xff0c;我们找到了 5 种有效的 Android SMS 备份解决方案&#xff0c;确保您的数字聊天和信息保持安全且可访问。…

标题:2025海外短剧爆发年:APP+H5双端系统开发,解锁全球流量与变现新大陆

描述&#xff1a; 2025年出海新风口&#xff01;深度解析海外短剧系统开发核心&#xff08;APPH5双端&#xff09;&#xff0c;揭秘高效开发策略与商业化路径&#xff0c;助您抢占万亿美元市场&#xff01; 全球娱乐消费模式正在剧变。2025年&#xff0c;海外短剧市场已从蓝海…

解决RAGFlow(v0.19.0)有部分PDF无法解析成功的问题。

ragflow版本为&#xff1a;v0.19.0 1.解析的时候报错&#xff1a;Internal server error while chunking: Coordinate lower is less than upper。 看报错怀疑是分片的问题&#xff0c;于是把文档的切片方法中的“建议文本块大小”数值&#xff08;默认512&#xff09;调小&…