P5692 手牵手走向明天
P5692 手牵手走向明天
有一个长度为 的序列 ,有 次操作。
- 给定 ,将 中等于 的数全部改成 。
- 给定 ,找到 满足 且 ,并要求 最小,求这个最小值,无解输出
-1
。
,时限 ,空限 。
sol
「弑尽破净第四分块」加强版。
无难度评分。
相较于 P5397 天降之物,这题是对区间修改和查询,所以我们不能再用原先的根号分治。
考虑序列分块。
对于答案在一个块内的情况显然可以预处理。
但这里如果是开一个 的三维数组的话空间是 级别的。
注意到每个块内只有 个数,所以可以使用类似于离散化的技巧,对于每个数,把它映射到一个标号,这样空间就是 开得下了,可 获取⼀个数在某个块中的标号, 的定义为第 个块内,数 与离散化后的 的最短距离。
如果不在一个块内的话,由于我们要求距离最小,那么每个块中可能成为答案的,只有这个数第一次出现的位置和最后一次出现的位置,维护每个块内每个数第一次和最后一次出现的位置,然后扫一遍,维护 和 各自最后一次出现的位置即可,单次时间复杂度 。
对于散块的查询直接扫过去,单次时间复杂度为 。
再看修改,枚举每一个块,假设一个块中最开始有 个颜色,那么修改 为 :
- 无 :跳过。
- 有 无 :改标号即可。
- 有 有 :对于 以外的 个颜色,每一个颜色都需要进行 次修改,然后合并 的颜色信息也是 的,总时间复杂度是 ,并且每次操作完 减少一。
考虑怎么更新 数组的信息,容易想到,枚举每个其他颜色,取 即可。
那么一个块最多产生多少次操作?
因为 最大为 ,所以一个块中的操作次数其实是 级别的,所以总操作次数就是 。
最后看散块修改,最大的问题在于关于 的距离怎么修改,因为做的是 ,直接修改似乎不好办。
考虑到,先用 的代价将这一块的 的实际值求出来,然后对于 的相关信息直接求一遍, 的相关信息也直接求一遍,这一部分的复杂度是 的。
需要注意的是,散块的修改可能增加一个颜色,但是散块最多只会增加 个颜色,所以时间复杂度还是对的。
所以,总时间复杂度为 ,总空间复杂度为 。
。
#include <cstdio>
#include <cmath>
#include <cstring>
namespace Fread
{
const int SIZE = 1 << 21;
char buf[SIZE], *S, *T;
inline char getchar()
{
if (S == T)
{
T = (S = buf) + fread(buf, 1, SIZE, stdin);
if (S == T)
return '\n';
}
return *S++;
}
}
namespace Fwrite
{
const int SIZE = 1 << 21;
char buf[SIZE], *S = buf, *T = buf + SIZE;
inline void flush()
{
fwrite(buf, 1, S - buf, stdout);
S = buf;
}
inline void putchar(char c)
{
*S++ = c;
if (S == T)
flush();
}
struct NTR
{
~NTR()
{
flush();
}
} ztr;
}
#ifdef ONLINE_JUDGE
#define getchar Fread::getchar
#define putchar Fwrite::putchar
#endif
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
inline void write(int x)
{
if (x < 0)
{
putchar('-');
x = -x;
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
const int N = 1e5 + 3, S = 3e2 + 3, T = 6e2 + 3, inf = 0x3f3f3f3f;
int n, m, q, a[N];
int sqrtn, bl[N], L[T], R[T];
int dis[T][S][S], disl[T][S], disr[T][S], pot[T][N], rpot[T][S], lim[T];
int rt[T][S], col[N], fa[N];
int find(int x)
{
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
inline int min(int x, int y)
{
return x < y ? x : y;
}
inline int max(int x, int y)
{
return x > y ? x : y;
}
inline void chkmin(int &x, int y)
{
x = min(x, y);
}
inline void chkmax(int &x, int y)
{
x = max(x, y);
}
inline void swap(int &x, int &y)
{
x ^= y ^= x ^= y;
}
inline void upd_dis(int t, int _L, int _R, int y)
{
int tl = -inf;
const int &py = pot[t][y];
for (int j = _L; j <= _R; ++j)
{
if (col[find(j)] == y)
tl = j;
chkmin(dis[t][py][pot[t][col[find(j)]]], j - tl);
chkmin(dis[t][pot[t][col[find(j)]]][py], j - tl);
}
tl = inf;
for (int j = _R; j >= _L; --j)
{
if (col[find(j)] == y)
tl = j;
chkmin(dis[t][py][pot[t][col[find(j)]]], tl - j);
chkmin(dis[t][pot[t][col[find(j)]]][py], tl - j);
}
}
inline void init()
{
sqrtn = sqrt(n * 2.2 / 5);
for (int i = 1, c = 1, j; i <= n; i = j + 1, ++c)
{
L[c] = i, R[c] = j = min(n, i + sqrtn);
for (int t = L[c]; t <= R[c]; ++t)
bl[t] = c;
}
m = bl[n];
memset(disl, 60, sizeof disl);
memset(disr, -61, sizeof disr);
memset(dis, 60, sizeof dis);
for (int t = 1; t <= m; ++t)
{
for (int i = L[t]; i <= R[t]; ++i)
{
if (!pot[t][a[i]])
{
rpot[t][pot[t][a[i]] = ++lim[t]] = a[i];
col[rt[t][lim[t]] = i] = a[i];
}
fa[i] = rt[t][pot[t][a[i]]];
}
for (int i = L[t]; i <= R[t]; ++i)
if (fa[i] == i)
upd_dis(t, L[t], R[t], a[i]);
for (int i = R[t]; i >= L[t]; --i)
disl[t][pot[t][a[i]]] = i;
for (int i = L[t]; i <= R[t]; ++i)
disr[t][pot[t][a[i]]] = i;
}
}
inline int calc(int l, int r, int x, int y)
{
int ans = inf, lx = -inf, ly = -inf;
for (int i = l; i <= r; ++i)
{
if (col[find(i)] == x)
lx = i, chkmin(ans, i - ly);
if (col[find(i)] == y)
ly = i, chkmin(ans, i - lx);
}
return ans;
}
inline int query(int l, int r, int x, int y)
{
if (x == y)
{
bool flag = 0;
if (bl[l] == bl[r])
for (int i = l; i <= r; ++i)
flag |= col[find(i)] == x;
else
{
for (int i = l; i <= R[bl[l]]; ++i)
flag |= col[find(i)] == x;
for (int i = L[bl[r]]; i <= r; ++i)
flag |= col[find(i)] == x;
for (int i = bl[l] + 1; i <= bl[r] - 1; ++i)
flag |= pot[i][x] > 0;
}
return -1 + flag;
}
if (bl[l] == bl[r])
return calc(l, r, x, y);
int ans = min(calc(l, R[bl[l]], x, y), calc(L[bl[r]], r, x, y));
int lx = disr[bl[l]][pot[bl[l]][x]];
if (lx < l)
lx = -inf;
int ly = disr[bl[l]][pot[bl[l]][y]];
if (ly < l)
ly = -inf;
for (int i = bl[l] + 1; i <= bl[r] - 1; ++i)
{
if (pot[i][x])
chkmin(ans, disl[i][pot[i][x]] - ly);
if (pot[i][y])
chkmin(ans, disl[i][pot[i][y]] - lx);
if (pot[i][x])
lx = disr[i][pot[i][x]];
if (pot[i][y])
ly = disr[i][pot[i][y]];
chkmin(ans, dis[i][pot[i][x]][pot[i][y]]);
}
int rx = disl[bl[r]][pot[bl[r]][x]];
if (rx > r)
rx = inf;
int ry = disl[bl[r]][pot[bl[r]][y]];
if (ry > r)
ry = inf;
return min(ans, min(rx - ly, ry - lx));
}
inline void deleted(int t, int px)
{
const int < = lim[t];
swap(rt[t][px], rt[t][lt]);
for (int i = 1; i <= lt; ++i)
swap(dis[t][px][i], dis[t][lt][i]), swap(dis[t][i][px], dis[t][i][lt]);
swap(disl[t][px], disl[t][lt]), swap(disr[t][px], disr[t][lt]);
swap(rpot[t][px], rpot[t][lt]), swap(pot[t][rpot[t][px]], px), --lim[t];
}
inline void cg(int t, int l, int r, int x, int y)
{
int ret = 0, &px = pot[t][x], &py = pot[t][y];
const int &_L = L[t], &_R = R[t];
for (int i = l; i <= r; ++i)
ret += col[find(i)] == x;
if (!ret)
return;
if (!py)
{
rpot[t][py = ++lim[t]] = y, disl[t][py] = inf, disr[t][py] = -inf;
for (int i = 1; i <= lim[t]; ++i)
dis[t][py][i] = dis[t][i][py] = inf;
}
for (int i = 1; i <= lim[t]; ++i)
dis[t][px][i] = dis[t][i][px] = inf;
for (int i = _L; i <= _R; ++i)
{
a[i] = col[find(i)];
rt[t][pot[t][a[i]]] = 0;
}
for (int i = l; i <= r; ++i)
if (a[i] == x)
{
a[i] = y;
--ret;
}
for (int i = _L; i <= _R; ++i)
ret += a[i] == x;
if (!ret)
deleted(t, px);
for (int i = _L; i <= _R; ++i)
{
if (!rt[t][pot[t][a[i]]])
col[rt[t][pot[t][a[i]]] = i] = a[i];
fa[i] = rt[t][pot[t][a[i]]];
}
upd_dis(t, _L, _R, y);
if (ret)
upd_dis(t, _L, _R, x);
for (int i = _R; i >= _L; --i)
disl[t][pot[t][a[i]]] = i;
for (int i = _L; i <= _R; ++i)
disr[t][pot[t][a[i]]] = i;
if (!ret)
px = 0;
}
inline void modify(int l, int r, int x, int y)
{
if (x == y)
return;
if (bl[l] == bl[r])
return cg(bl[l], l, r, x, y), void();
cg(bl[l], l, R[bl[l]], x, y);
cg(bl[r], L[bl[r]], r, x, y);
for (int t = bl[l] + 1; t <= bl[r] - 1; ++t)
{
int &px = pot[t][x], &py = pot[t][y];
if (!px)
continue;
if (!py)
{
rpot[t][py = px] = y, px = 0, col[rt[t][py]] = y;
continue;
}
fa[rt[t][px]] = rt[t][py], rt[t][px] = 0;
for (int i = lim[t]; i >= 1; --i)
{
chkmin(dis[t][py][i], dis[t][px][i]);
chkmin(dis[t][i][py], dis[t][i][px]);
}
chkmin(disl[t][py], disl[t][px]);
chkmax(disr[t][py], disr[t][px]);
for (int i = lim[t]; i >= 1; --i)
dis[t][px][i] = dis[t][i][px] = inf;
deleted(t, px), px = 0;
}
}
int op, l, r, x, y;
int main()
{
n = read(), q = read();
for (int i = 1; i <= n; ++i)
a[i] = read();
init();
for (int i = 1; i <= q; ++i)
{
op = read(), l = read(), r = read(), x = read(), y = read();
if (op == 1)
modify(l, r, x, y);
else
{
int ans = query(l, r, x, y);
write(ans > n ? -1 : ans);
putchar('\n');
}
}
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122044
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!