P5397 [Ynoi2018] 天降之物
第
lxl 给出的标答是根号分治,不过也有序列分块的做法,只不过非常需要卡常。
我们先对序列分块。接着我们考虑怎么处理询问。
显然询问的结果有两种:
-
在块内的答案。这种可以通过预处理
表示第 块中 到 的最小距离。即我们每一块暴力 枚举,显然预处理时间复杂度为 。因为每一块最多只有 个不同数,我们可以对每块的数离散化,这样空间复杂度也可以降低到 。 -
横跨多块的答案。我们从前往后每块搜索,如果这一块有
,那么肯定要在前面接一个 ,所以我们对于每一块处理 和 表示 块中 第一次出现位置和最后一次出现。那么前面我们想求的就可以轻松算出了。
两种答案取
而较难的则是修改:
我们假设有一块
-
如果块中没有
,那么跳过。 -
如果块中没有
,那么我们把 在 块中离散化的值改为 。 -
如果即有
也有 。我们先更新 的 和 ,然后暴力枚举 ,用 更新 。由于离散化过,这一步是 的。
你可能会问这最后一步的复杂度好像是错误的。但实际上,对于某一块,如果一直是
至此我们得到了一个
然而交上去,T 了一片。于是需要卡常。
几个卡常技巧:
-
保证数组内存访问连续。我的代码中有
表示 块中 离散化结果。而将其改为 后快了许多, 和 同理。 -
减少不必要的循环。
-
调块长。经尝试,我的代码的最优块长约在
左右。 -
Fread 快读。
-
选个人少的时间交。
然后给一个交了几十次过了一次,再交又会 T 的代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
using namespace std;
const int N = 1e5 + 5, blo = 203, M = 494;
#define get(x) ((x) / blo + 1)
#define BF_SIZE 100000
bool IOerr = 0;
inline char nc() {
static char buf[BF_SIZE], * p1 = buf + BF_SIZE, * pend = buf + BF_SIZE;
if (p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BF_SIZE, stdin);
if (pend == p1) { IOerr = 1; return -1; }
}
return *p1++;
}
inline bool bla(char ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; }
inline int read()
{
char ch;
int x = 0;
while (bla(ch = nc()));
if (IOerr) { return 0; }
for (x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = (x << 1) + (x << 3) + ch - '0');
return x;
}
int n, m, a[N];
int b[N], idx;
short v[N][M];
int f[N][M], e[N][M];
short dis[M][blo + 1][blo + 1];
int L, R;
#define gl(i) (((i) - 1) * blo)
const short INF = 32765;
inline int query(int& x, int& y)
{
int lx = 0, ly = 0, ans = 10000000;
for (int i = L; i <= R; i = -~i)
{
if (ans == 1) return ans;
if (v[x][i] && v[y][i])
{
ans = min(ans, (int)dis[i][v[x][i]][v[y][i]]);
}
if (v[x][i] && ly)
{
ans = min(ans, f[v[x][i]][i] - ly);
}
if (v[y][i] && lx)
{
ans = min(ans, f[v[y][i]][i] - lx);
}
if (v[x][i]) lx = e[v[x][i]][i];
if (v[y][i]) ly = e[v[y][i]][i];
}
return ans;
}
inline void modify(int& x, int& y)
{
if (x == y) return;
for (int i = 1; i <= R; i = -~i)
{
int xx(v[x][i]), yy(v[y][i]);
if (!xx) continue;
if (!yy)
{
v[y][i] = v[x][i];
v[x][i] = 0;
}
else
{
f[yy][i] = min(f[yy][i], f[xx][i]);
e[yy][i] = max(e[yy][i], e[xx][i]);
f[xx][i] = e[xx][i] = 0;
for (int j = 1; j <= blo; j = -~j)
{
dis[i][yy][j] = dis[i][j][yy] = min(dis[i][j][yy], dis[i][j][xx]);
dis[i][xx][j] = dis[i][j][xx] = INF;
}
dis[i][yy][xx] = dis[i][xx][yy] = INF;
v[x][i] = 0;
}
}
}
inline void write(int x)
{
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int main()
{
memset(dis, 0x3f, sizeof dis);
n = read(), m = read();
for (int i = 1; i <= n; i++) a[i] = read();
L = 1, R = get(n);
int nl(1);
int nr(blo - 1);
idx = 0;
for (int j(nl); j <= nr; j = -~j) b[++idx] = a[j];
sort(b + 1, b + idx + 1);
for (int j(nl); j <= nr; j = -~j)
{
int na = lower_bound(b + 1, b + idx + 1, a[j]) - b;
v[a[j]][1] = na;
if (!f[na][1]) f[na][1] = j;
e[na][1] = j;
dis[1][na][na] = 0;
}
for (int j(nl); j <= nr; j = -~j)
{
for (int k(j + 1); k <= nr; k++)
{
int nx(v[a[j]][1]), ny(v[a[k]][1]), g(min(dis[1][nx][ny], (short)(k - j)));
dis[1][nx][ny] = g;
dis[1][ny][nx] = g;
}
}
for (int i = 2; i <= R; i++)
{
int nl(gl(i));
int nr(gl(i + 1) - 1);
if (nr > n) nr = n;
idx = 0;
for (int j = nl; j <= nr; j++) b[++idx] = a[j];
sort(b + 1, b + idx + 1);
for (int j(nl); j <= nr; j++)
{
int na(lower_bound(b + 1, b + idx + 1, a[j]) - b);
v[a[j]][i] = na;
if (!f[na][i]) f[na][i] = j;
e[na][i] = j;
dis[i][na][na] = 0;
}
for (int j(nl); j <= nr; j = -~j)
{
for (int k(j + 1); k <= nr; k = -~k)
{
int nx(v[a[j]][i]), ny(v[a[k]][i]), g(min(dis[i][nx][ny], (short)(k - j)));
dis[i][nx][ny] = g;
dis[i][ny][nx] = g;
}
}
}
int lans = 0;
while (m--)
{
int opt(read()), x(read()), y(read());
x ^= lans, y ^= lans;
if (opt == 2)
{
int res(query(x, y));
if (res > n)
{
printf("Ikaros\n");
lans = 0;
}
else
{
write(lans = res);
putchar('\n');
}
}
else
{
modify(x, y);
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现