1 条题解
-
0
自动搬运
来自洛谷,原作者为

win114514
过去的我正在消散,未来的我模糊不清,唯一能相信的只有现在的自己。搬运于
2025-08-24 23:05:34,当前版本为作者最后更新于2024-11-05 16:58:31,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
很有意思的一道题。
思路
首先将相邻一样的数合并,每个元素变成一个二元组,表示数与出现次数。
考虑什么时候不能合并。
我们发现假如充分合并后,现在有连续的三个数 ,以及他们各自的出现次数 。
如果 。
我们想要合并这三个,必须要先把 合并成 。
但是如果做不到的话,那么这三个数就一定不可能合并了。
相当于整个序列从这里断开了。
这样的话,整个序列是一堆单峰序列。
考虑末尾追加一个二元组 会有什么影响:
-
序列尾部元素与 相等。
累加 即可。
-
序列元素少于两个。
直接插入即可。
-
序列尾部大于 , 或尾部大于倒数第二个。
同样直接插入即可。
-
除了以上情况,我们就需要一些处理了。
将末尾与倒数第二个提出来,记为 。
首先我们判断能否将 提升至 ,如果可以,我们就先将其提升,然后再递归插入。
如果不可以,我们可以插入一个极大值作为分割符,然后将 的贡献往 与 上累加,再递归插入。
线段树维护即可。
时间复杂度:。
Code
#include <bits/stdc++.h> using namespace std; int n; int a[100010]; struct Node { int ns = 0; vector<pair<int, int>> cr{}; inline void init(int x) { vector<pair<int, int>>{{x, 1}}.swap(cr); ns = x; } inline void add(pair<int, int> x) { if (x.second) ns = max(ns, x.first + __lg(x.second)); if (cr.size() && cr.back().first == x.first) { cr.back().second += x.second; if (cr.back().second) ns = max(ns, cr.back().first + __lg(cr.back().second)); } else if (cr.size() <= 1) cr.push_back(x); else if (cr.back().first > x.first) cr.push_back(x); else if (cr.size() >= 2 && cr.back().first > cr[cr.size() - 2].first) cr.push_back(x); else { auto y = cr.back(); cr.pop_back(); auto z = cr.back(); int d = min(30, min(x.first, z.first) - y.first); if ((y.second & (-y.second)) >= (1 << d)) add({y.first + d, y.second >> d}), add(x); else { if (__lg(y.second) >= z.first - y.first) add({z.first, y.second >> (z.first - y.first)}); add({1e9, 0}); if (__lg(y.second) >= x.first - y.first) x.second += y.second >> (x.first - y.first); add(x); } } } inline friend Node operator+(Node a, Node b) { Node c = a; c.ns = max(b.ns, c.ns); for (auto i : b.cr) c.add(i); return c; } } ns, d[200010]; inline void build(int p, int l, int r) { if (l == r) d[p].init(a[l]); else { int mid = (l + r) >> 1; build(mid<<1, l, mid); build(mid<<1|1, mid + 1, r); d[p] = d[mid<<1] + d[mid<<1|1]; } } inline void upd(int p, int l, int r, int k) { if (l == r) d[p].init(a[l]); else { int mid = (l + r) >> 1; if (mid >= k) upd(mid<<1, l, mid, k); else upd(mid<<1|1, mid + 1, r, k); d[p] = d[mid<<1] + d[mid<<1|1]; } } inline void ask(int p, int l, int r, int L, int R) { if (L <= l && r <= R) ns = ns + d[p]; else { int mid = (l + r) >> 1; if (L <= mid) ask(mid<<1, l, mid, L, R); if (mid < R) ask(mid<<1|1, mid + 1, r, L, R); } } void prepare_game(vector<int> A) { n = A.size(); for (int i = 1; i <= n; i++) a[i] = A[i - 1]; build(1, 1, n); } int play_game(int l, int r) { ns.cr.clear(); ns.ns = 0; ns.add({1e9, 0}); ask(1, 1, n, l + 1, r + 1); ns.add({1e9, 0}); return ns.ns; } void update_game(int p, int v) { a[p + 1] = v; upd(1, 1, n, p + 1); } -
- 1
信息
- ID
- 10935
- 时间
- 4000ms
- 内存
- 1000MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者