题目链接: [Ynoi Easy Round 2024] TEST_133

首先历史最大加,吉司机跑不掉了,维护历史最大加标记以及历史最大,那么根据吉司机标记思想更新操作应该为

\[new \Leftarrow \max{(h_{max},a_i+h_{addMax})}
\]

新的历史最大值,由原来的历史最大值和当前点的值加上更新过程中最大的历史加标记二者取最优。

看题目条件,好家伙时间限制 \(40s\)。有个很烦的限制 \(a_i < x\) 的最大历史值。那么很明显的是一个区间内的历史最大值是很好都拿到的,每个数也是很好都拿到的,但是这里面不是所有数都有贡献,有啥办法可以快速找到需要判断的数?emmmm,有序好像就特别好做了。直接二分出最大的满足 \(a_j<x\) 的 \(j\)。区间内要有序,然后 \(40s\) 时限的提醒。自然而然想到了根号级做法。分块的入门 P2801 教主的魔法。维护块内有序即可二分。

需要维护什么信息仔细想想。

1.首先每个块需要有 lazy 标记。非常简单:最基本的区间加标记和吉司机思想的历史最大加标记。

2.块内有序,是按照 \(a_i\) 进行排序,而我们显然在查询时可以知道贡献区间为 \(1 \sim j\),其中 \(j\) 是可以二分出来的最大的满足 \(a_j < x\) 的 \(j\)。而我们需要知道这个前缀区间的最大历史值。很简单。维护块内有序的同时,并维护对应排序后的 \(a_i\) 对应位置的 \(h_{max}\) 的前缀最大值。

然后,然后就完了。剩下的就是卡常和常规的 DS 码工了。

考虑几个点的复杂度

1、对于重构一个块,根号重构。我们需要复制一份对应的 \((a_i,h_i)\),然后排序,然后再更新块内的 \(PrefixMax_{h_i}\)。这个复杂度显然是

\[O(2\times \sqrt{n}+\sqrt{n}\log{\sqrt{n}})=O(\sqrt{n}\log{\sqrt{n}})
\]

2、对于一次 pushDown 更新标记,我们就是正常一遍块内遍历更新。根据上述先后更新 \(h_{max}\) 与 \(a_i\)。复杂度为 \(O(\sqrt{n})\)

3、二分出块内小等于 \(<x\) 的最大历史最值前缀max(区间max具有单调性)。这个复杂度显然为 \(O(\log{\sqrt{n}})\)

4、修改时,还是老规矩,单块内就暴力,多块就散块暴力,整块打标记更新。需要注意的是散块需要记得先 pushDown 以后再更新。然后优化下常数,其实可以开个 vis 数组,也可以当做标记的一种,记录哪些块发生了变化,需要在后续查询中重构。因为重构的复杂度是较高 的,所以我们也可以当做 lazy 去写。这里的复杂度显然是 \(O(\sqrt{n})\)

5、查询时,需要把该重构的重构一下。然后注意整块不要 pushDown,不然每个块都 pushDown 复杂度就错了,应该当做标记永久化的思想:查询时用 \(x-add\) 就行了,不需要 pushDown 以后的新 \(a_i\) 去算。然后就纯每个块二分。复杂度为 \(O(\sqrt{n}\log{\sqrt{n}})\)

6、建块时每个块需要 rebuild 一下,显然是 \(O(\sqrt{n} \times \sqrt{n}\log{\sqrt{n}})=O(n\log{\sqrt{n}})\),当然也可以全部记录为 \(vis\) 为 true 后更新。

参考代码
  1. #include <bits/stdc++.h>
  2. //#pragma GCC optimize("Ofast,unroll-loops")
  3. #define isPbdsFile
  4. #ifdef isPbdsFile
  5. #include <bits/extc++.h>
  6. #else
  7. #include <ext/pb_ds/priority_queue.hpp>
  8. #include <ext/pb_ds/hash_policy.hpp>
  9. #include <ext/pb_ds/tree_policy.hpp>
  10. #include <ext/pb_ds/trie_policy.hpp>
  11. #include <ext/pb_ds/tag_and_trait.hpp>
  12. #include <ext/pb_ds/hash_policy.hpp>
  13. #include <ext/pb_ds/list_update_policy.hpp>
  14. #include <ext/pb_ds/assoc_container.hpp>
  15. #include <ext/pb_ds/exception.hpp>
  16. #include <ext/rope>
  17. #endif
  18. using namespace std;
  19. using namespace __gnu_cxx;
  20. using namespace __gnu_pbds;
  21. typedef long long ll;
  22. typedef long double ld;
  23. typedef pair<int, int> pii;
  24. typedef pair<ll, ll> pll;
  25. typedef tuple<int, int, int> tii;
  26. typedef tuple<ll, ll, ll> tll;
  27. typedef unsigned int ui;
  28. typedef unsigned long long ull;
  29. typedef __int128 i128;
  30. #define hash1 unordered_map
  31. #define hash2 gp_hash_table
  32. #define hash3 cc_hash_table
  33. #define stdHeap std::priority_queue
  34. #define pbdsHeap __gnu_pbds::priority_queue
  35. #define sortArr(a, n) sort(a+1,a+n+1)
  36. #define all(v) v.begin(),v.end()
  37. #define yes cout<<"YES"
  38. #define no cout<<"NO"
  39. #define Spider ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
  40. #define MyFile freopen("..\\input.txt", "r", stdin),freopen("..\\output.txt", "w", stdout);
  41. #define forn(i, a, b) for(int i = a; i <= b; i++)
  42. #define forv(i, a, b) for(int i=a;i>=b;i--)
  43. #define ls(x) (x<<1)
  44. #define rs(x) (x<<1|1)
  45. #define endl '\n'
  46. //用于Miller-Rabin
  47. [[maybe_unused]] static int Prime_Number[13] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
  48. template <typename T>
  49. int disc(T* a, int n)
  50. {
  51. return unique(a + 1, a + n + 1) - (a + 1);
  52. }
  53. template <typename T>
  54. T lowBit(T x)
  55. {
  56. return x & -x;
  57. }
  58. template <typename T>
  59. T Rand(T l, T r)
  60. {
  61. static mt19937 Rand(time(nullptr));
  62. uniform_int_distribution<T> dis(l, r);
  63. return dis(Rand);
  64. }
  65. template <typename T1, typename T2>
  66. T1 modt(T1 a, T2 b)
  67. {
  68. return (a % b + b) % b;
  69. }
  70. template <typename T1, typename T2, typename T3>
  71. T1 qPow(T1 a, T2 b, T3 c)
  72. {
  73. a %= c;
  74. T1 ans = 1;
  75. for (; b; b >>= 1, (a *= a) %= c)if (b & 1)(ans *= a) %= c;
  76. return modt(ans, c);
  77. }
  78. template <typename T>
  79. void read(T& x)
  80. {
  81. x = 0;
  82. T sign = 1;
  83. char ch = getchar();
  84. while (!isdigit(ch))
  85. {
  86. if (ch == '-')sign = -1;
  87. ch = getchar();
  88. }
  89. while (isdigit(ch))
  90. {
  91. x = (x << 3) + (x << 1) + (ch ^ 48);
  92. ch = getchar();
  93. }
  94. x *= sign;
  95. }
  96. template <typename T, typename... U>
  97. void read(T& x, U&... y)
  98. {
  99. read(x);
  100. read(y...);
  101. }
  102. template <typename T>
  103. void write(T x)
  104. {
  105. if (typeid(x) == typeid(char))return;
  106. if (x < 0)x = -x, putchar('-');
  107. if (x > 9)write(x / 10);
  108. putchar(x % 10 ^ 48);
  109. }
  110. template <typename C, typename T, typename... U>
  111. void write(C c, T x, U... y)
  112. {
  113. write(x), putchar(c);
  114. write(c, y...);
  115. }
  116. template <typename T11, typename T22, typename T33>
  117. struct T3
  118. {
  119. T11 one;
  120. T22 tow;
  121. T33 three;
  122. bool operator<(const T3 other) const
  123. {
  124. if (one == other.one)
  125. {
  126. if (tow == other.tow)return three < other.three;
  127. return tow < other.tow;
  128. }
  129. return one < other.one;
  130. }
  131. T3() { one = tow = three = 0; }
  132. T3(T11 one, T22 tow, T33 three) : one(one), tow(tow), three(three)
  133. {
  134. }
  135. };
  136. template <typename T1, typename T2>
  137. void uMax(T1& x, T2 y)
  138. {
  139. if (x < y)x = y;
  140. }
  141. template <typename T1, typename T2>
  142. void uMin(T1& x, T2 y)
  143. {
  144. if (x > y)x = y;
  145. }
  146. constexpr int N = 5e5 + 10;
  147. constexpr ll INF = 1e18 + 10;
  148. int pos[N];
  149. constexpr int SIZE = sqrt(N);
  150. constexpr int CNT = (N + SIZE - 1) / SIZE;
  151. int s[CNT + 1], e[CNT + 1];
  152. ll a[N]; //当前序列
  153. ll his[N]; //单点最大历史值
  154. pll sortA[N]; //块内有序,并且附带对应的单点历史最大值
  155. ll preHisMax[N]; //块内前缀历史最大值
  156. bool vis[CNT + 1]; //需要重构块
  157. struct Tag
  158. {
  159. ll add; //加法标记
  160. ll hadd; //历史最大加
  161. } tag[CNT + 1];
  162. inline void rebuild(const int id)
  163. {
  164. forn(i, s[id], e[id])sortA[i] = pll(a[i], his[i]);
  165. sort(sortA + s[id], sortA + e[id] + 1); //按当前序列排序
  166. //更新块内基于原序列为有序序列的前缀历史最大值
  167. preHisMax[s[id]] = sortA[s[id]].second;
  168. forn(i, s[id]+1, e[id])uMax(preHisMax[i] = sortA[i].second, preHisMax[i - 1]);
  169. }
  170. inline void push_down(const int id)
  171. {
  172. if (!tag[id].add and !tag[id].hadd)return;
  173. forn(i, s[id], e[id])uMax(his[i], a[i] + tag[id].hadd), a[i] += tag[id].add; //更新当前序列并且更新当前历史最大值
  174. tag[id] = {0, 0}; //清空lazy
  175. }
  176. //二分出块内小于x的最大历史最值前缀max(区间max具有单调性)
  177. inline ll binary(const int id, const ll x)
  178. {
  179. int l = s[id], r = e[id];
  180. if (sortA[l].first >= x)return -INF;
  181. while (l < r)
  182. {
  183. if (const int mid = l + r + 1 >> 1; sortA[mid].first < x)l = mid;
  184. else r = mid - 1;
  185. }
  186. return max(preHisMax[l], sortA[l].first + tag[id].hadd);
  187. }
  188. inline ll query(const int l, const int r, const ll x)
  189. {
  190. const int L = pos[l], R = pos[r];
  191. if (L == R)
  192. {
  193. if (vis[L])rebuild(L), vis[L] = false;
  194. ll ans = -INF;
  195. forn(i, l, r)if (a[i] + tag[L].add < x)uMax(ans, max(his[i], a[i] + tag[L].hadd));
  196. return ans;
  197. }
  198. if (vis[L])rebuild(L), vis[L] = false;
  199. if (vis[R])rebuild(R), vis[R] = false;
  200. ll ans = -INF;
  201. forn(i, l, e[L])if (a[i] + tag[L].add < x)uMax(ans, max(his[i], a[i] + tag[L].hadd));
  202. forn(i, s[R], r)if (a[i] + tag[R].add < x)uMax(ans, max(his[i], a[i] + tag[R].hadd));
  203. forn(i, L+1, R-1)
  204. {
  205. if (vis[i])rebuild(i), vis[i] = false;
  206. if (ll t = binary(i, x - tag[i].add); t != -INF)uMax(ans, t);
  207. }
  208. return ans;
  209. }
  210. inline void add(const int l, const int r, const ll x)
  211. {
  212. const int L = pos[l], R = pos[r];
  213. if (L == R)
  214. {
  215. push_down(L);
  216. forn(i, l, r)uMax(his[i], a[i] += x);
  217. vis[L] = true;
  218. return;
  219. }
  220. push_down(L), push_down(R);
  221. forn(i, l, e[L])uMax(his[i], a[i] += x);
  222. forn(i, s[R], r)uMax(his[i], a[i] += x);
  223. vis[L] = vis[R] = true;
  224. forn(i, L+1, R-1)uMax(tag[i].hadd, tag[i].add += x);
  225. }
  226. int n, q;
  227. inline void solve()
  228. {
  229. cin >> n >> q;
  230. int siz = sqrt(n);
  231. int cnt = (n + siz - 1) / siz;
  232. forn(i, 1, n)cin >> a[i], his[i] = a[i], pos[i] = (i - 1) / siz + 1;
  233. forn(i, 1, cnt)s[i] = (i - 1) * siz + 1, e[i] = i * siz;
  234. e[cnt] = n;
  235. forn(i, 1, cnt)rebuild(i);
  236. forn(i, 1, q)
  237. {
  238. int op, l, r, val;
  239. cin >> op >> l >> r >> val;
  240. if (op == 1)add(l, r, val);
  241. else
  242. {
  243. if (ll ans = query(l, r, val); ans == -INF)cout << "-inf" << endl;
  244. else cout << ans << endl;
  245. }
  246. }
  247. }
  248. signed int main()
  249. {
  250. Spider
  251. //------------------------------------------------------
  252. int test = 1;
  253. // read(test);
  254. // cin >> test;
  255. forn(i, 1, test)solve();
  256. // while (cin >> n, n)solve();
  257. // while (cin >> test)solve();
  258. }

P9993 [Ynoi Easy Round 2024] TEST_133 题解的更多相关文章

  1. Codeforces Round #539 Div1 题解

    Codeforces Round #539 Div1 题解 听说这场很适合上分QwQ 然而太晚了QaQ A. Sasha and a Bit of Relax 翻译 有一个长度为\(n\)的数组,问有 ...

  2. UOJ Easy Round#7

    UOJ Easy Round#7 传送门:http://uoj.ac/contest/35 题解:http://matthew99.blog.uoj.ac/blog/2085 #1 题意: 在一个(2 ...

  3. Codeforces Round #543 Div1题解(并不全)

    Codeforces Round #543 Div1题解 Codeforces A. Diana and Liana 给定一个长度为\(m\)的序列,你可以从中删去不超过\(m-n*k\)个元素,剩下 ...

  4. Codeforces Round #545 Div1 题解

    Codeforces Round #545 Div1 题解 来写题解啦QwQ 本来想上红的,结果没做出D.... A. Skyscrapers CF1137A 题意 给定一个\(n*m\)的网格,每个 ...

  5. CF Educational Round 78 (Div2)题解报告A~E

    CF Educational Round 78 (Div2)题解报告A~E A:Two Rival Students​ 依题意模拟即可 #include<bits/stdc++.h> us ...

  6. Educational Codeforces Round 64 部分题解

    Educational Codeforces Round 64 部分题解 不更了不更了 CF1156D 0-1-Tree 有一棵树,边权都是0或1.定义点对\(x,y(x\neq y)\)合法当且仅当 ...

  7. CF Round #580(div2)题解报告

    CF Round #580(div2)题解报告 T1 T2 水题,不管 T3 构造题,证明大约感性理解一下 我们想既然存在解 \(|a[n + i] - a[i]| = 1\) 这是必须要满足的 既然 ...

  8. Educational Codeforces Round 64部分题解

    Educational Codeforces Round 64部分题解 A 题目大意:给定三角形(高等于低的等腰),正方形,圆,在满足其高,边长,半径最大(保证在上一个图形的内部)的前提下. 判断交点 ...

  9. 【题解】Comet OJ Round 70 简要题解

    [题解]Comet OJ Round 70 简要题解 A 将放在地上的书按照从小到大排序后,问题的本质就变成了合并两个序列使得字典序最小.可以直接模拟归并排序.直接用循环和std::merge实现这个 ...

  10. Codeforces Round div2 #541 题解

    codeforces Round #541 abstract: I构造题可能代码简单证明很难 II拓扑排序 III并查集 启发式排序,带链表 IV dp 处理字符串递推问题 V 数据结构巧用:于二叉树 ...

随机推荐

  1. windows 系统关闭占用端口的应用

    开发中有时候开发工具把程序关闭了,但是后台并没有真正关闭程序,导致再次启动相同端口的程序时报端口已经被使用的错误,这时如何强制关闭已占用的端口 1.打开dos对话框 2.查找被占用的端口的进程号 ne ...

  2. ASP.Net Core 5.0 MVC Session的添加,及它与Cookie的关系

    1.在控制器上新增一个方法 public IActionResult SessionAndCookie() { string result = HttpContext.Session.GetStrin ...

  3. excel如何自动获取本周工作日的日期显示作为标题(周一至周五)

    一.背景: 每周发周报的标题格式为:本周一到本周五的日期内容,如下:但是每隔一周发送的时候需要改一下周报标题里面的日期,比较麻烦目前的需求是通过函数自动化生成,根据当前的日期去定位出本周一的日期以及本 ...

  4. AMBA Bus介绍_01

    AMBA总线概述 系统总线简介 AMBA 2.0 AHB - 高性能Bus APB - 外设Bus AHB ASB APB AHB 组成部分 APB组成部分 AMBA协议其他有关问题 DMA DMA ...

  5. 【Spring 5核心原理】1设计模式

    1.1开闭原则 开闭原则(open-closed principle,OCP)是指一个软件实体(如类,模块和函数)应该对扩展开放,对修改关闭.所谓的开闭,也正是对扩展和修改两个行为的一个原则. 强调用 ...

  6. 探讨Java死锁的现象和解决方法

    死锁是多线程编程中常见的问题,它会导致线程相互等待,无法继续执行.在Java中,死锁是一个需要注意和解决的重要问题.让我们通过一系列详细的例子来深入了解Java死锁的现象和解决方法. 1. 什么是死锁 ...

  7. [转帖]日常Bug排查-读从库没有原子性?

    https://zhuanlan.zhihu.com/p/658508920 3 人赞同了该文章 日常Bug排查系列都是一些简单Bug排查.问题虽小,但经常遇到,了解这些问题,会让我们少走点弯路,提升 ...

  8. Oracle process/session/cursor/tx/tm的简单学习

    Oracle process/session/cursor/tx/tm的简单学习 Oracle的部署模式 Oracle安装时有专用模式和共享模式的区别 共享模式(Shared mode): 在共享模式 ...

  9. [转帖]Unix Domain Socket– IPC通信机制

    什么是Unix Domain Socket 基于socket的框架上发展出一种IPC机制,就是UNIX Domain Socket.虽然网络socket也可用于同一台主机的进程间通讯(通过loopba ...

  10. [转帖]configure 各种配置

    https://api.dandelioncloud.cn/article/details/1487329970564485121 -build=编译该软件所使用的平台 -host=该软件将运行的平台 ...