当前位置: 首页 > news >正文

P4168 [Violet] 蒲公英 Solution

Description

给定序列 a = ( a 1 , a 2 , ⋯ , a n ) a=(a_1,a_2,\cdots,a_n) a=(a1,a2,,an),有 q q q 个查询 ( l , r ) (l,r) (l,r).
对每个查询求 a l ⋯ r a_{l\cdots r} alr 的众数,若有多个取最小的.
强制在线.
真实的 l = ( l ′ + lastans − 1 ) m o d n ) + 1 , r = ( r ′ + lastans − 1 ) m o d n ) + 1 l=(l^\prime+\textit{lastans}-1)\bmod n)+1,r=(r^\prime+\textit{lastans}-1)\bmod n)+1 l=(l+lastans1)modn)+1,r=(r+lastans1)modn)+1,若 l > r l>r l>r 则交换两者.

Limitations

1 ≤ n ≤ 4 × 1 0 4 1\le n\le 4\times 10^4 1n4×104
1 ≤ n ≤ 5 × 1 0 4 1\le n\le 5\times 10^4 1n5×104
1 ≤ a i ≤ 1 0 9 1\le a_i\le 10^9 1ai109
1 ≤ l ≤ r ≤ n 1\le l\le r\le n 1lrn

Solution

区间众数无法用线段树维护,但 n , m n,m n,m 不大,可以用分块.
首先 a i a_i ai 很大,需要先离散化.
然后借助一个桶 cnt \textit{cnt} cnt 预处理 pre i , j \textit{pre}_{i,j} prei,j 表示 a i a_i ai 在第 1 ∼ j 1\sim j 1j 块的出现次数.
还有 mode i , j \textit{mode}_{i,j} modei,j 表示第 i ∼ j i\sim j ij 块的众数.

考虑查询,如果 [ l , r ] [l,r] [l,r] 在单块内或相邻块间,我们直接暴力.
否则,我们统计两端散块内的 a i a_i ai中间整块内 以及 两端 的出现次数,存入 cnt \textit{cnt} cnt 中,并求出这部分的众数.
然后查询整块间的众数,以及 [ l , r ] [l,r] [l,r] 间这个数的出现次数(整块散块分开算),然后判断并更新答案.
有几个坑:

  • mode i , j \textit{mode}_{i,j} modei,j 前要先继承 mode i , j − 1 \textit{mode}_{i,j-1} modei,j1 的结果.
  • 答案要转化为离散化前的.
  • cnt \textit{cnt} cnt 用完要清空,可以只清空用过的部分.

B = n B=\sqrt n B=n ,时间复杂度 O ( ( n + m ) n ) O((n+m)\sqrt n) O((n+m)n ).

Code

4.09 KB , 1.29 s , 9.62 MB (in total, C++20 with O2) 4.09\text{KB},1.29\text{s},9.62\text{MB}\;\texttt{(in total, C++20 with O2)} 4.09KB,1.29s,9.62MB(in total, C++20 with O2)
fastio 删了

#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 {}
using fastio::read;
using fastio::write;struct Block {int n, v, size, blocks;vector<int> a, belong, L, R, cnt;vector<vector<int>> pre, mode; inline Block() {}inline Block(const vector<int>& _a, int _v) : v(_v), a(_a) {n = a.size();size = (int)sqrt(n);blocks = (n + size - 1) / size;belong.resize(n);L.resize(blocks);R.resize(blocks);for (int i = 0; i < blocks; i++) {L[i] = i * size;R[i] = std::min(L[i] + size, n) - 1;for (int j = L[i]; j <= R[i]; j++) belong[j] = i;}pre.resize(blocks, vector<int>(v, 0));mode.resize(blocks, vector<int>(blocks, -1));cnt.resize(v);init();}// Prepareinline void init() {for (int i = 0; i < n; i++) for (int j = belong[i]; j < blocks; j++) pre[j][a[i]]++;for (int i = 0; i < blocks; i++) {clear();for (int j = i; j < blocks; j++) {if (j > i) mode[i][j] = mode[i][j - 1];for (int k = L[j]; k <= R[j]; k++) {cnt[a[k]]++;update(mode[i][j], a[k], cnt[a[k]]);}}}clear();}// Updateinline void update(int& x, int y, int c) {if (x == -1 || (c > cnt[x]) || (c == cnt[x] && y < x)) x = y;}// Clearinline void clear() { cnt.assign(v, 0); }inline void clear(int l, int r) {for (int i = l; i <= r; i++) cnt[a[i]] = 0;}// Countinline int count_block(int bl, int br, int k) { return pre[br - 1][k] - pre[bl][k];}inline int count_part(int l, int r, int k) {int res = 0;for (int i = l; i <= r; i++) res += (a[i] == k);return res;}// Add to the bucketinline void add(int l, int r, int bl, int br) {for (int i = l; i <= r; i++)if (!cnt[a[i]]) cnt[a[i]] += count_block(bl, br, a[i]);}// Update the answerinline void get_part(int& ans, int l, int r) {for (int i = l; i <= r; i++) {cnt[a[i]]++;update(ans, a[i], cnt[a[i]]);}}// Queryinline int query(int l, int r) {const int bl = belong[l], br = belong[r];if (br - bl <= 2) {int ans = -1;get_part(ans, l, r), clear(l, r);return ans;}int ans = -1;add(l, R[bl], bl, br), add(L[br], r, bl, br);get_part(ans, l, R[bl]), get_part(ans, L[br], r);int k = mode[bl + 1][br - 1];int cntk = (count_block(bl, br, k) + count_part(l, R[bl], k) + count_part(L[br], r, k));update(ans, k, cntk);clear(l, R[bl]), clear(L[br], r);return ans;}
};signed main() {ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);const int n = read<int>(), m = read<int>();vector<int> a(n);for (int i = 0; i < n; i++) a[i] = read<int>();auto disc = a;sort(disc.begin(), disc.end());disc.erase(unique(disc.begin(), disc.end()), disc.end());for (int i = 0; i < n; i++) {a[i] = lower_bound(disc.begin(), disc.end(), a[i]) - disc.begin();}Block blk(a, disc.size());for (int i = 0, l, r, lst = 0; i < m; i++) {l = read<int>(), r = read<int>();l = (l + lst - 1) % n;r = (r + lst - 1) % n;if (l > r) swap(l, r);write(lst = disc[blk.query(l, r)]);putchar_unlocked('\n');}return 0;
}

相关文章:

  • Cordova开发自定义插件的方法
  • 我国“东数西算”工程对数据中心布局的长期影响
  • 双目测量中的将视差图重投影成三维坐标图
  • 2025.5.5总结
  • 42. 接雨水(相向双指针/前后缀分解),一篇文章讲透彻
  • 【中间件】brpc_基础_单例
  • Scrapy分布式爬虫实战:高效抓取的进阶之旅
  • 直方图反向投影
  • 多语言笔记系列:Polyglot Notebooks 中运行 BenchmarkDotnet 基准测试
  • Hive安装与配置教程
  • 《冰雪三职业》:战士玩法攻略!
  • UniGetUI 使用指南:轻松管理 Windows 软件(包括CUDA)
  • 模型训练实用之梯度检查点
  • 头歌实验MySQL数据库 - 复杂查询(二)
  • 深入解析Semantic Kernel中的聊天历史记录对象
  • Gradio全解20——Streaming:流式传输的多媒体应用(6)——RT-DETR模型构建视频流目标检测系统
  • STM32教程:DMA原理及结构分析(基于STM32F103C8T6最小系统板标准库开发)*详细教程*
  • C++类与对象深度解析:从基础到应用
  • 《Java 高并发程序设计》笔记
  • 【言语理解】片段阅读之标题拟定(5)
  • 沪幼升小网上报名明起开始,是否参与民办摇号怎么定?
  • 李学明谈笔墨返乡:既耕春圃,念兹乡土
  • 辽宁召开假期安全生产工作调度会:绝不允许层层失守,绝不允许“带病运行”
  • 给3亿老人爆改房子,是门好生意吗?
  • 巴菲特首次明确批评贸易战,“投资界春晚”有哪些看点?一文速览
  • 美国警方:爱达荷州交通事故致7人死亡,8名伤者预计无生命危险