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);
}
posted @ 2025-08-31 10:59  CJzdc  阅读(2)  评论(0)    收藏  举报