P5692 手牵手走向明天

有一个长度为 n n n 的序列 a a a,有 m m m 次操作。

  • 给定 l , r , x , y l,r,x,y l,r,x,y,将 a l , a l + 1 , a l + 2 , ⋯ , a r a_l,a_{l+1},a_{l+2},\cdots,a_r al​,al+1​,al+2​,⋯,ar​ 中等于 x x x 的数全部改成 y y y。
  • 给定 l , r , x , y l,r,x,y l,r,x,y,找到 i , j i,j i,j 满足 i , j ∈ [ l , r ] i,j\in[l,r] i,j∈[l,r] 且 a i = x , a j = y a_i=x,a_j=y ai​=x,aj​=y,并要求 ∣ i − j ∣ |i-j| ∣i−j∣ 最小,求这个最小值,无解输出 -1

1 ≤ n , m , a i ≤ 1 0 5 1 \leq n,m,a_i\leq 10^5 1≤n,m,ai​≤105,时限 1.50 s 1.50\text{s} 1.50s,空限 512 MB 512\text{MB} 512MB。

sol

「弑尽破净第四分块」加强版。

无难度评分。

相较于 P5397 天降之物,这题是对区间修改和查询,所以我们不能再用原先的根号分治。

考虑序列分块。

对于答案在一个块内的情况显然可以预处理。

但这里如果是开一个 d i s [ i ] [ j ] [ k ] dis[i][j][k] dis[i][j][k] 的三维数组的话空间是 n 2 n n^2\sqrt n n2n ​ 级别的。

注意到每个块内只有 n \sqrt n n ​ 个数,所以可以使用类似于离散化的技巧,对于每个数,把它映射到一个标号,这样空间就是 n n n\sqrt n nn ​ 开得下了,可 O ( 1 ) \mathcal O(1) O(1) 获取⼀个数在某个块中的标号, d i s [ i ] [ j ] [ k ] dis[i][j][k] dis[i][j][k] 的定义为第 i i i 个块内,数 j j j 与离散化后的 k k k 的最短距离。

如果不在一个块内的话,由于我们要求距离最小,那么每个块中可能成为答案的,只有这个数第一次出现的位置和最后一次出现的位置,维护每个块内每个数第一次和最后一次出现的位置,然后扫一遍,维护 x x x 和 y y y 各自最后一次出现的位置即可,单次时间复杂度 O ( n ) \mathcal O(\sqrt n) O(n ​)。

对于散块的查询直接扫过去,单次时间复杂度为 O ( n ) \mathcal O(\sqrt n) O(n ​)。

再看修改,枚举每一个块,假设一个块中最开始有 m m m 个颜色,那么修改 x x x 为 y y y:

  • 无 x x x:跳过。
  • 有 x x x 无 y y y:改标号即可。
  • 有 x x x 有 y y y:对于 x , y x,y x,y 以外的 m − 2 m-2 m−2 个颜色,每一个颜色都需要进行 O ( 1 ) \mathcal O(1) O(1) 次修改,然后合并 x , y x,y x,y 的颜色信息也是 O ( m ) \mathcal O(m) O(m) 的,总时间复杂度是 O ( m ) O(m) O(m),并且每次操作完 m m m 减少一。

考虑怎么更新 d i s dis dis 数组的信息,容易想到,枚举每个其他颜色,取 min ⁡ \min min 即可。

那么一个块最多产生多少次操作?

因为 m m m 最大为 n \sqrt{n} n ​ ,所以一个块中的操作次数其实是 O ( n ) \mathcal O(n) O(n) 级别的,所以总操作次数就是 O ( n n ) O(n\sqrt{n}) O(nn ​)。

最后看散块修改,最大的问题在于关于 y y y 的距离怎么修改,因为做的是 min ⁡ \min min,直接修改似乎不好办。

考虑到,先用 O ( n ) O(\sqrt{n}) O(n ​) 的代价将这一块的 a i a_i ai​ 的实际值求出来,然后对于 y y y 的相关信息直接求一遍, x x x 的相关信息也直接求一遍,这一部分的复杂度是 O ( n ) O(\sqrt{n}) O(n ​) 的。

需要注意的是,散块的修改可能增加一个颜色,但是散块最多只会增加 n \sqrt n n ​ 个颜色,所以时间复杂度还是对的。

所以,总时间复杂度为 O ( ( n + m ) n ) \mathcal O((n+m)\sqrt n) O((n+m)n ​),总空间复杂度为 O ( n n ) \mathcal O(n \sqrt n) O(nn ​)。

2.76s / 398.59MB / 6.84KB C++98 O2 \text{2.76s / 398.59MB / 6.84KB C++98 O2} 2.76s / 398.59MB / 6.84KB C++98 O2。

#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
#endifinline 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 &lt = 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');}}
}

P5692 手牵手走向明天相关推荐

  1. 手牵手教你写代码,从入门到精通

    如果说到什么是好代码,我们肯定都能说出一堆规则,例如使用一致的格式和缩进.使用清晰的变量名和方法名.在必要时提供文档与注释.不要过度精简代码等等. 但是对于什么是烂代码,你有比较清晰的认识吗? 在 G ...

  2. Jenkins 与 Kubernetes 手牵手

    加入公众号一起发现美好技术 背景信息 虽然云原生时代有了 JenkinsX.Drone.Tekton 这样的后起之秀,但 Jenkins 这样一个老牌的 CI/CD 工具仍是各大公司主流的使用方案.比 ...

  3. 喜来登“手牵手”家庭计划率先亮相大中华区13家度假酒店

    为了使阖家出游的宾客获得更丰富多元的旅行体验,度过更多美妙的欢聚时光,万豪旅享家旗下深受宾客信赖与欢迎的全球化品牌 -- 喜来登酒店及度假村宣布在亚太区推出品牌的首个亲子体验项目 -- 喜来登&quo ...

  4. 手牵手,使用uni-app从零开发一款视频小程序 (系列上 准备工作篇)

    系列文章 手牵手,使用uni-app从零开发一款视频小程序 (系列上 准备工作篇) 手牵手,使用uni-app从零开发一款视频小程序 (系列下 开发实战篇) 前言 好久不见,很久没更新博客了,前段时间 ...

  5. python二值化特征_R与Python手牵手:特征工程(数值型变换)

    原标题:R与Python手牵手:特征工程(数值型变换) 作者:黄天元,复旦大学博士在读,目前研究涉及文本挖掘.社交网络分析和机器学习等.希望与大家分享学习经验,推广并加深R语言在业界的应用. 邮箱:h ...

  6. 金婚纪念:手牵手,度今生

    金婚纪念:手牵手,度今生 1967年9月19日,我与家人手牵手前往北京市西长安街派出所结婚登记,成为夫妇. 1966年,她从北邮毕业,后在某部机关任职(教授级总工程师),是对国家有贡献的通信专家. 婚 ...

  7. 手牵手走过喧嚣的人群

    喜欢那一种温馨的感觉,安静,浪漫! 一起手牵手走过喧嚣的人群的时候,那时怎样一种幸福.远比一万朵玫瑰更令人眷恋. 人的一生,要追求的东西太多了,如果要取舍的话,我坚持想要永恒的东西,我要那些可以持久的 ...

  8. 基于uni-app开发微信小程序__手牵手带你开发【懂你找图】项目

    前戏 某一天的夜里,敲完了代码之后便直接倒在床上睡着了,醒来时只记得梦里的一句话:"想要成为高手,就必须要大量实践,大量做项目,必须要把自己不会的东西全部吃透,不要得过且过.",猛 ...

  9. 手牵手,简单的甜蜜。

    刚刚走在校园里,看到前边一对情侣,手牵着手,一起向前走. 突然就觉得他们好甜蜜,好浪漫. -- 男孩子伸出手,我可以牵你的手吗? 女孩子低头羞涩的把手伸过去. 这就是爱情. 简单.浪漫.美好! 不明白 ...

最新文章

  1. php简单代码大全,征集常用的PHP简单代码
  2. 光流 | OpenCV中的光流有关函数
  3. LightGBM参数的贝叶斯搜索(有boost_from_average参数设置)
  4. Windows 11 新功能:管理蓝牙设备将不再困难
  5. java处理pdf文件——iText的使用
  6. matlab的lambda,matlab lambda 级数
  7. MODIS数据下载——订单模式下载tif影像
  8. 国产linux聊天软件,程序员的全平台聊天软件:Rocket.Chat
  9. SitePoint播客#87:MeltSheep和FireRock
  10. “3D游戏之父”考古“诺基亚时代”手游,网友:求支持智能手机!
  11. 《R语言数据挖掘》读书笔记:五、聚类分析
  12. 快速入池淘宝猜你喜欢方法技巧
  13. 如何达到高效的网络信息传播
  14. ubuntu桌面版下配置锐捷客户端
  15. Python 写入XLSX文件的几种方法
  16. Android U盘测速
  17. JDK8Stream API
  18. 秦皇岛 2019 CCPC区域赛 部分代码
  19. Windows下怎么用you-get下载视频
  20. python换行符是什么?

热门文章

  1. ARM芯片内部堆栈的理解及MAP文件的查看
  2. android bitmap回收,android BitMap回收
  3. 全息网御上榜《CCSIP 2022中国网络安全产业全景图》
  4. 0基础学Python有多难?
  5. native聊天界面 react_ReactNative 仿微信聊天 App 实例分享|RN 仿朋友圈
  6. H6062FNL 普思Pulse 网络变压器
  7. 一个HashMap跟面试官扯了半个小时
  8. win10任务栏怎么还原到下面_Win10如何快速显示桌面?
  9. 除了编码,还要会说话(1)
  10. 什么情况下单独计算机械台班,投标or签证,机械台班价如何确认?