【Ynoi2018】天降之物
【Ynoi2018】天降之物
题意#
给定一个长为 \(n\) 的序列 \(a\),支持两种操作:
-
将所有 \(a_p = x\) 修改为 \(y\)。
-
查询 \(\min(|i-j|)\),满足 \(a_i = x \and a_j = y\) 或者 \(a_i = y \and a_j = x\)。
题解#
考虑序列分块,首先考虑块内贡献,设块长为 \(B\),由于分块的 \(B\) 一般为根号级别,直接将一个块内数离散化,预处理一个数在块内出现的第一个位置和最后一个位置,记录 \(ins_{i,j}\) 表示 \((i, j)\) 的答案。
预处理是 \(O(\frac{n}{B}(B^2 + B\log B))\) 的复杂度。
接着先思考询问,一个块内的处理完了,直接查,如果不在一个块,一定是前一个在块最后,后一个在块开头。前面处理的直接用上,注意答案不一定在相邻的两个块内(卡了很久)。
然后是修改,分类讨论一下
- 如果 \(x\) 没出现,直接跳过。
- 如果 \(y\) 没出现,显然总颜色数不变,直接让 \(y\) 继承 \(x\) 的信息即可。
- 如果 \(x\) 和 \(y\) 都出现,对于 \(ins\) 我们重新遍历一遍块更新答案即可。另外东西直接取 \(\min\) 或者 \(max\) 即可。由于每次修改会让一个块少一个颜色,所以总复杂度是 \(O(n\sqrt n)\) 的。
注意修改完要把 \(x\) 在这个块内标记为不存在。
注意一点细节卡个常就过了。
#include <bits/stdc++.h> namespace FileHeader { using int16 = int16_t; using int32 = int32_t; using int64 = int64_t; using uint32 = uint32_t; using uint64 = uint64_t; #define ep emplace #define eb emplace_back #define all(x) x.begin(), x.end() FILE* fin, * fout, * ferr; int32 read() { int32 t = 0, f = 0; char ch = fgetc(fin); for (; !isdigit(ch); ch = fgetc(fin)) f ^= (ch == '-'); for (; isdigit(ch); ch = fgetc(fin)) t = (t << 1) + (t << 3) + (ch ^ 48); return f ? -t : t; } class Iterator { public: Iterator(int32 _val = 0): _val(_val) {} bool operator !=(const Iterator &other) const { return this->_val != other._val; } int32 operator *() { return this->_val; } int32 operator ++() { return ++this->_val; } private: int32 _val; }; class Range { public: Range(int32 _l = 0, int32 _r = 0): _begin(_l), _end(_r + 1) {} Iterator begin() { return Iterator(this->_begin); } Iterator end() { return Iterator(this->_end); } private: int32 _begin, _end; }; } using namespace FileHeader; namespace Solution_Of_P5397 { static const int32 N = 100010, B = 255, M = N / B + 10; static const int32 inf32 = 0x3f3f3f3f; int32 n, m, bl; int32 a[N], b[N]; int32 L[M], R[M], len[M]; int16 ins[N][M]; int16 inp[N][M]; int32 fir[N], sec[N]; template<typename T> inline void cmin(T &x, T y) { return x = (x < y ? x : y), void(); } template<typename T> inline void cmax(T &x, T y) { return x = (x > y ? x : y), void(); } inline void init(int32 bl, int32 l, int32 r) { L[bl] = l, R[bl] = r; int32 P = R[bl - 1]; std::vector<int32> numric; for (auto i : Range(l, r)) numric.eb(a[i]); std::sort(all(numric), [&](int32 a, int32 b) { return a < b; }); numric.erase(std::unique(all(numric)), numric.end()); len[bl] = static_cast<int32>(numric.size()); for (int32 i = l; i <= r; ++i) { b[i] = std::lower_bound(all(numric), a[i]) - numric.begin() + 1; inp[a[i]][bl] = b[i]; } for (int32 i = r; i >= l; --i) fir[P + b[i]] = i; for (int32 i = l; i <= r; ++i) sec[P + b[i]] = i; for (int32 i = 1; i <= len[bl]; ++i) std::memset(ins[P + i], 64, (len[bl] + 1) << 1); for (auto i : Range(l, r)) for (auto j : Range(i + 1, r)) { int32 a1 = inp[a[i]][bl], a2 = inp[a[j]][bl]; if (a1 > a2) std::swap(a1, a2); cmin(ins[P + a1][a2], int16(j - i)); } return void(); } inline int32 trans(int16 x) { if (x == 0x3f3f) return 0x3f3f3f3f; return static_cast<int32>(x); } inline int32 query(int32 x, int32 y) { if (x == y) { for (auto i : Range(1, bl)) if (inp[x][i]) return 0; return 0x3f3f3f3f; } int32 ans = inf32; int32 lst1 = -inf32, lst2 = -inf32; for (auto i : Range(1, bl)) { int16 a1 = inp[x][i], a2 = inp[y][i]; int32 P = R[i - 1]; if (a1) cmin(ans, fir[P + a1] - lst2); if (a2) cmin(ans, fir[P + a2] - lst1); if (a1) lst1 = sec[P + a1]; if (a2) lst2 = sec[P + a2]; if (a1 > a2) std::swap(a1, a2); if (a1 && a2) cmin(ans, trans(ins[P + a1][a2])); } return ans; } inline void modify1(int32 bl, int32 x, int32 y) { inp[y][bl] = inp[x][bl]; inp[x][bl] = 0; return void(); } inline void modify2(int32 bl, int32 x, int32 y) { int16 a1 = inp[x][bl], a2 = inp[y][bl]; int32 P = R[bl - 1]; cmin(fir[P + a2], fir[P + a1]); cmax(sec[P + a2], sec[P + a1]); fir[P + a1] = sec[P + a1] = 0; if (a1 < a2) { for (auto i : Range(1, a1)) cmin(ins[P + i][a2], ins[P + i][a1]); for (auto i : Range(a1 + 1, a2)) cmin(ins[P + i][a2], ins[P + a1][i]); for (auto i : Range(a2 + 1, len[bl])) cmin(ins[P + a2][i], ins[P + a1][i]); } else { for (auto i : Range(1, a2)) cmin(ins[P + i][a2], ins[P + i][a1]); for (auto i : Range(a2 + 1, a1)) cmin(ins[P + a2][i], ins[P + i][a1]); for (auto i : Range(a1 + 1, len[bl])) cmin(ins[P + a2][i], ins[P + a1][i]); } inp[x][bl] = 0; return void(); } inline void modify(int32 x, int32 y) { if (x == y) return void(); for (auto i : Range(1, bl)) { if (!inp[x][i]) continue; if (!inp[y][i]) modify1(i, x, y); else modify2(i, x, y); } return void(); } inline void main() { fin = stdin, fout = stdout, ferr = stderr; // fin = fopen("data.in", "r"); // fout = fopen("data.out", "w"); n = read(), m = read(); for (auto i : Range(1, n)) a[i] = read(); bl = (n - 1) / B + 1; for (auto i : Range(1, bl)) init(i, (i - 1) * B + 1, std::min(n, i * B)); for (auto t : Range(1, m)) { static int32 op, x, y, lastans = 0; op = read(), x = read() ^ lastans, y = read() ^ lastans; if (op == 1) modify(x, y); if (op == 2) { lastans = query(x, y); if (lastans == inf32) lastans = 0, fputs("Ikaros\n", fout); else fprintf(fout, "%d\n", lastans); } } return void(); } } signed main() { return Solution_Of_P5397::main(), 0; }
作者: xxcxu
出处:https://www.cnblogs.com/Maraschino/p/17726422.html
本站使用「CC BY 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话