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

LG P4119 [Ynoi2018] 未来日记 Solution

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;
}

相关文章:

  • Spring Boot 自动参数校验
  • Mistral 推出全新开发者平台Agents API
  • AE 脚本表达式错误 Default ColorSelectionwhile (true){ break;} }
  • 10000+套PPT模版合集和简历模版 【多种系列风格】免费下载
  • Java对象克隆:从浅到深的奥秘
  • 最卸载器——Geek Uninstaller 使用指南
  • [SC]SystemC在CPU/GPU验证中的应用(三)
  • 79. 单词搜索-极致优化,可行性剪枝和顺序剪枝
  • L56.【LeetCode题解】 电话号码的字母组合
  • Python打卡训练营学习记录Day41
  • NW994NX734美光固态闪存NX737NX740
  • Redis缓存问题重点详解
  • 三步问题 --- 动态规划
  • 快速阅读源码
  • 目前主流图像分类模型的详细对比分析
  • 8088单板机C语言sprintf()格式化串口输出---Prj04
  • 【Net】TCP粘包与半包
  • 算法打卡12天
  • Microsoft Word使用技巧分享(本科毕业论文版)
  • 【SLAM自救笔记1】:苟活
  • 化妆培训网站开发/it培训机构口碑排名
  • 全国网站建设哪家好/搜索引擎营销分析
  • 怎样给公司做免费网站/cps推广平台
  • 滁州市城市建设投资有限公司网站/安徽网络关键词优化
  • 外国做水吧设计的网站/网络推广方案怎么写
  • 摄影网站建站/哈尔滨网络优化推广公司