P11236 [KTSC 2024 R1] 水果游戏
这题需要带修,考虑一些比较好维护的做法。
从小往大考虑当前值 \(v\),对于值 \(=v\) 的长为 \(c\) 的连续段,设其左右分别是 \(a,b\),设 \(d=\min(a,b)-v\)。
如果 \(2^d|c\),那么我们可以把这一段缩起来,变成一个值为 \(v+d\),长为 \(\tfrac{c}{2^d}\) 的段,然后和两边合并。
如果 \(2^d\not\mid c\),那么两边实际上是独立的,我们可以插入一个 \((+\infty,1)\) 的段,然后把两边加上 \((v+d,\lfloor\tfrac{c}{2^d}\rfloor)\) 和 \((v+d,\lfloor\tfrac{c}{2^d}\rfloor)\) 两段。
可以发现,当我们无法操作时,整个序列是单峰的!而值域保证了段数为 \(O(\log n)\) 量级。
因此可以直接线段树维护,做到 \(O(q\log n(v+\log n))\)。
感觉上这个题就是通过值域扫描,把序列转换为了一个简单的、好维护的形式。
代码多写了一个 \(\log\)。
#include <bits/stdc++.h>
using namespace std;
using pii = pair<int, int> ;
template <typename T> void Chkmax(T &x, T y) { x = max(x, y); }
const int kN = 1e5 + 5, kS = 4e5 + 5;
int n;
int a[kN];
struct Info {
int ans;
vector<pii> vec;
Info() { ans = 0, vec = vector<pii> {}; }
int GetL(int s, int t) {
int cnt = vec[s].second;
for(int i = s; i < t; i++) {
cnt >>= (vec[i + 1].first - vec[i].first);
cnt += vec[i + 1].second;
}
return cnt;
}
int GetR(int s, int t) {
int cnt = vec[s].second;
for(int i = s; i > t; i--) {
cnt >>= (vec[i - 1].first - vec[i].first);
cnt += vec[i - 1].second;
}
return cnt;
}
int Ans() {
int siz = vec.size();
int res = ans;
int p = max_element(vec.begin(), vec.end()) - vec.begin();
if(vec[p].first == 30) {
if(p) Chkmax(res, __lg(GetL(0, p - 1)) + vec[p - 1].first);
if(p + 1 < siz) Chkmax(res, __lg(GetR(siz - 1, p + 1)) + vec[p + 1].first);
}else {
int cnt = GetL(0, p) + GetR(siz - 1, p) - vec[p].second;
Chkmax(res, __lg(cnt) + vec[p].first);
}
return res;
}
};
Info operator + (Info x, Info y) {
if(x.vec.empty()) return y;
if(y.vec.empty()) return x;
Info ans;
ans.ans = max(x.ans, y.ans);
vector<pii> vec = x.vec, vecy = y.vec;
if(vec.back().first == vecy[0].first) {
vecy[0].second += vec.back().second;
vec.pop_back();
}
vec.insert(vec.end(), vecy.begin(), vecy.end());
while(1) {
int p = -1;
for(int i = 1; i + 1 < vec.size(); i++) {
int vl = vec[i - 1].first;
int vi = vec[i].first;
int vn = vec[i + 1].first;
if((vl >= vi) && (vn >= vi)) p = i;
}
if(p == -1) break;
int lst = vec[p - 1].first;
int cur = vec[p].first, cnt = vec[p].second;
int nxt = vec[p + 1].first;
int dif = min(lst, nxt) - cur;
Chkmax(ans.ans, cur + __lg(cnt));
if(!(cnt & ((1 << dif) - 1))) {
cnt >>= dif;
cur += dif;
if((lst == cur) && (nxt == cur)) {
vec[p - 1].second += cnt + vec[p + 1].second;
vec.erase(vec.begin() + p, vec.begin() + p + 2);
}else {
if(lst == cur) vec[p - 1].second += cnt;
else vec[p + 1].second += cnt;
vec.erase(vec.begin() + p);
}
}else {
if(cnt >= (1 << (lst - cur))) {
vec[p - 1].second += (cnt >> lst - cur);
}
if(cnt >= (1 << (nxt - cur))) {
vec[p + 1].second += (cnt >> nxt - cur);
}
if((lst == 30) && (nxt == 30)) {
vec.erase(vec.begin() + p, vec.begin() + p + 2);
}else if((lst == 30) || (nxt == 30)) {
vec.erase(vec.begin() + p);
}else vec[p] = pii {30, 1};
}
}
return ans.vec = vec, ans;
}
#define ls (o << 1)
#define rs (o << 1 | 1)
struct SGT {
Info info[kS];
void Up(int o) { info[o] = info[ls] + info[rs]; }
void Build(int o, int l, int r) {
if(l == r) {
info[o].ans = a[l];
info[o].vec = vector<pii> {pii {a[l], 1}};
return ;
}
int mid = (l + r) >> 1;
Build(ls, l, mid);
Build(rs, mid + 1, r);
Up(o);
}
void Modify(int o, int l, int r, int x, int v) {
if(l == r) {
info[o].ans = v;
info[o].vec = vector<pii> {pii {a[x] = v, 1}};
return ;
}
int mid = (l + r) >> 1;
if(mid < x) Modify(rs, mid + 1, r, x, v);
else Modify(ls, l, mid, x, v);
Up(o);
}
Info Query(int o, int l, int r, int x, int y) {
if((l > y) || (r < x)) return Info();
if((l >= x) && (r <= y)) return info[o];
int mid = (l + r) >> 1;
return Query(ls, l, mid, x, y) + Query(rs, mid + 1, r, x, y);
}
}sgt;
void prepare_game(vector<int> A) {
n = A.size();
for(int i = 1; i <= n; i++) a[i] = A[i - 1];
sgt.Build(1, 1, n);
}
int play_game(int l, int r) {
return sgt.Query(1, 1, n, l + 1, r + 1).Ans();
}
void update_game(int p, int v) {
sgt.Modify(1, 1, n, p + 1, v);
}
浙公网安备 33010602011771号