所以可以在从小到大枚举 x 的过程中,维护一个栈表示目前还没删掉的数和这些数的删除标记。然后在扫描 l 的过程中,维护另一个标记表示 >2ax 的个数。如果当前 ai≤2ax 就将 i 的删除标记加 1。否则将另一个标记加一,如果另一个标记到了 2 就停止扫描,并把栈里面删除标记为 2 的数删掉,并将 x 加到栈里。
voidbuild(int n){ for (N = 1; N <= n + 1; N <<= 1) {} for (int i = N; i <= N + n; ++i) mx[i] = i - N; for (int i = N - 1; i; --i) pushup(i); }
intquery(int l, int r){ int ret = 0; for (l += N - 1, r += N + 1; l ^ r ^ 1; l >>= 1, r >>= 1) { if (~l & 1) ret = get(ret, mx[l ^ 1]); if (r & 1) ret = get(ret, mx[r ^ 1]); } return ret; } } sgt;
voidgetl(){ staticint stk[kMaxN] = {0}, cnt[kMaxN] = {0}, tmp[kMaxN]; int top = 0; for (int i = 1; i <= n; ++i) { int now = 0, mx = 0, cur = top + 1; int64_t res = LLONG_MIN; for (int j = top; j; --j) { if (!mx) { mx = stk[j]; } elseif (a[stk[j]] < a[mx]) { res = std::max(res, a[i] % a[stk[j]] + a[stk[j]]); } else { res = std::max(res, a[i] % a[mx] + a[mx]); mx = stk[j]; } vecl[i].emplace_back(stk[j], res); if (a[stk[j]] > a[i] / 2) { if (++now == 2) break; } else { ++cnt[stk[j]]; } cur = j; } int m = 0; for (int j = cur; j <= top; ++j) if (cnt[stk[j]] < 2) tmp[++m] = stk[j]; top = cur - 1; for (int j = 1; j <= m; ++j) stk[++top] = tmp[j]; stk[++top] = i; std::reverse(vecl[i].begin(), vecl[i].end()); } }
voidgetr(){ staticint stk[kMaxN] = {0}, cnt[kMaxN] = {0}, tmp[kMaxN]; int top = 0; for (int i = n; i; --i) { int now = 0, mx = 0, cur = top + 1; int64_t res = LLONG_MIN; for (int j = top; j; --j) { if (!mx) { mx = stk[j]; } elseif (a[stk[j]] < a[mx]) { res = std::max(res, a[i] % a[stk[j]] + a[stk[j]]); } else { res = std::max(res, a[i] % a[mx] + a[mx]); mx = stk[j]; } vecr[i].emplace_back(stk[j], res); if (a[stk[j]] > a[i] / 2) { if (++now == 2) break; } else { ++cnt[stk[j]]; } cur = j; } int m = 0; for (int j = cur; j <= top; ++j) if (cnt[stk[j]] < 2) tmp[++m] = stk[j]; top = cur - 1; for (int j = 1; j <= m; ++j) stk[++top] = tmp[j]; stk[++top] = i; std::reverse(vecr[i].begin(), vecr[i].end()); } }
voidprework(){ sgt.build(n); getl(), getr(); }
int64_tF(int x, int l, int r, int mx){ int64_t ret = LLONG_MIN; int y = sgt.query(l, x - 1), z = sgt.query(x + 1, r); if (y && y != mx) ret = std::max(ret, a[y] + a[x] % a[y]); if (z && z != mx) ret = std::max(ret, a[z] + a[x] % a[z]); auto it1 = std::lower_bound(vecl[x].begin(), vecl[x].end(), std::pair<int, int64_t>{l, LLONG_MIN}); auto it2 = std::lower_bound(vecr[x].begin(), vecr[x].end(), std::pair<int, int64_t>{r, LLONG_MAX}, std::greater<>()); if (it1 != vecl[x].end()) ret = std::max(ret, it1->second); if (it2 != vecr[x].end()) ret = std::max(ret, it2->second); return ret; }
int64_tquery(int l, int r){ int x = sgt.query(l, r), y = get(sgt.query(l, x - 1), sgt.query(x + 1, r)); return std::max(F(x, l, r, y) + a[y], F(y, l, r, x) + a[x] % a[y]); }
voiddickdreamer(){ std::cin >> n >> q >> tp; for (int i = 1; i <= n; ++i) std::cin >> a[i]; prework(); int64_t lastans = 0; for (int i = 1; i <= q; ++i) { int l, r; std::cin >> l >> r; l = (l + lastans * tp - 1) % n + 1; r = (r + lastans * tp - 1) % n + 1; std::cout << (lastans = query(l, r)) << '\n'; } }