簡單資料結構,但本蒟蒻覺得並不簡單吶!
容易發現這題的幾個好用的性質:
1.只要被第一個操作影響的都能夠保持單調,容易一起維護。
2.操作都是全域性的!
3.沒被操作一影響的都可以表示為 \(ki+a_i\) 的形式。
利用這些性質,我們考慮把沒被操作一影響的項放在 \(S\) 集合,被操作一影響的項放在 \(T\) 集合。現在我們考慮動態維護這兩個東西,事實上我們可以先知道每一項是在什麼時候從 \(S\) 進入 \(T\) 的(顯然初始每一項都在 \(S\))。
每次我們進行操作一時,都會把所有滿足 \(a_i\ge v-ki\) 的所有項併入 \(T\),這種一次函式的形式啟發我們維護一個凸包,上面每個點為 \((i,a_i)\),然後維護一個上凸包,但是凸包太大了,不好修改,怎麼辦?我們發現刪點與重構凸包複雜度非常不均,所以考慮分塊,我們這樣每次刪掉一個點,再 \(\mathcal{O}(\sqrt n)\) 重構即可。因為只會刪掉 \(n\) 個點,所以複雜度是對的,但是這裡有個小問題,就是我們單次操作找每個塊內凸包的點有可能退化到 \(\mathcal{O}(n)\),沒關係,我們的 \(k\) 是單調的,每個塊內維護個雙指標即可。
對答案的貢獻用樹狀陣列可以簡單維護。
然後考慮維護 \(T\),首先對於 \(1\) 操作相當於是一段字尾推平,線段樹上二分隨便做。對於操作二的貢獻線上段樹上維護增加次數 \(delta\),並且維護可提供貢獻的點 \(sum\),因為線段樹上可以產生貢獻的點並不連續。對於最大值的維護也是簡單的,知道區間中最右邊的在 \(T\) 中的點就知道最大值了。
時間複雜度 \(\mathcal{O}(n\sqrt n)\),這裡 \(n,q\) 同級。
程式碼:
#include <bits/stdc++.h>
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; ++ i)
#define rrp(i, l, r) for (int i = r; i >= l; -- i)
#define pii pair <int, int>
#define eb emplace_back
#define inf 1000000000
#define id(x, y) n * (x - 1) + y
#define ls p << 1
#define rs ls | 1
using namespace std;
constexpr int N = 2e5 + 5, M = (1ll << 31) - 1, P = 998244353;
constexpr double PI = acos (-1.0);
inline int rd () {
int x = 0, f = 1;
char ch = getchar ();
while (! isdigit (ch)) {
if (ch == '-') f = -1;
ch = getchar ();
}
while (isdigit (ch)) {
x = (x << 1) + (x << 3) + ch - 48;
ch = getchar ();
}
return x * f;
}
int qpow (int x, int y) {
int ret = 1;
for (; y; y >>= 1, x = x * x % P) if (y & 1) ret = ret * x % P;
return ret;
}
namespace seg {
class node {
public:
int sum, val, mx, R, cnt, tag1, tag2;
} t[N << 2];
void clear () {
rep (i, 1, N * 4 - 1) {
t[i].sum = t[i].val = 0;
t[i].mx = t[i].R = t[i].cnt = 0;
t[i].tag1 = - 1; t[i].tag2 = 0;
}
}
void merge (node &ret, node x, node y) {
ret.sum = x.sum + y.sum;
ret.val = x.val + y.val;
ret.mx = max (x.mx, y.mx);
ret.R = max (x.R, y.R);
ret.cnt = x.cnt + y.cnt;
}
void cov (int p, int val) {
t[p].val = t[p].cnt * val;
t[p].mx = val;
t[p].tag1 = val;
t[p].tag2 = 0;
}
void add (int p, int x) {
t[p].val += t[p].sum * x;
t[p].mx += t[p].R * x;
t[p].tag2 += x;
}
void psd (int p) {
if (t[p].tag1 > -1) {
cov (ls, t[p].tag1);
cov (rs, t[p].tag1);
t[p].tag1 = -1;
}
if (t[p].tag2) {
add (ls, t[p].tag2);
add (rs, t[p].tag2);
t[p].tag2 = 0;
}
}
int find (int p, int l, int r, int x) {
if (l == r) {
if (t[p].val >= x) return l; else return 0;
}
int mid = l + r >> 1;
psd (p);
if (t[ls].mx >= x) return find (ls, l, mid, x);
else return find (rs, mid + 1, r, x);
}
void modify (int p, int l, int r, int L, int R, int v) {
if (L <= l && r <= R) return cov (p, v), void ();
int mid = l + r >> 1; psd (p);
if (L <= mid) modify (ls, l, mid, L, R, v);
if (R > mid) modify (rs, mid + 1, r, L, R, v);
merge (t[p], t[ls], t[rs]);
}
void upd (int p, int l, int r, int x, int k) {
if (l == r) {
t[p].sum = x, t[p].cnt = 1;
t[p].R = x, t[p].val = t[p].mx = k;
return ;
} psd (p); int mid = l + r >> 1;
if (x <= mid) upd (ls, l, mid, x, k);
else upd (rs, mid + 1, r, x, k);
merge (t[p], t[ls], t[rs]);
}
int qry (int p, int l, int r, int L, int R) {
if (L <= l && r <= R) return t[p].val;
int mid = l + r >> 1, ret = 0; psd (p);
if (L <= mid) ret += qry (ls, l, mid, L, R);
if (R > mid) ret += qry (rs, mid + 1, r, L, R);
return ret;
}
}
int n, m, q;
int a[N];
struct FWT {
int c[N];
int lb (int x) { return x & -x; }
void upd (int x, int y) {
for (; x <= n; c[x] += y, x += lb (x)) ;
}
int qry (int x) {
int ret = 0;
for (; x; ret += c[x], x -= lb (x)) ;
return ret;
}
} s, t;
class node {
public:
int opt;
int l, r;
} g[N];
class Dot {
public:
int x, y;
friend Dot operator + (const Dot &a, const Dot &b) {
return (Dot) {a.x + b.x, a.y + b.y};
}
friend Dot operator - (const Dot &a, const Dot &b) {
return (Dot) {a.x - b.x, a.y - b.y};
}
friend int operator * (const Dot &a, const Dot &b) {
return a.x * b.y - a.y * b.x;
}
} d[N];
vector <int> vec[N];
class block {
public:
int l, r, ld, rd;
int stk[505];
void build () {
l = 1, r = 0;
rep (i, ld, rd) {
if (d[i].y < 0) continue;
while (l < r && (d[stk[r]] - d[stk[r - 1]]) * (d[i] - d[stk[r]]) >= 0) -- r;
stk[++ r] = i;
}
}
void del (int k, int id, int x) {
while (l <= r) {
while (l < r && d[stk[l]].x * k + d[stk[l]].y <= d[stk[l + 1]].x * k + d[stk[l + 1]].y) ++ l;
if (d[stk[l]].x * k + d[stk[l]].y >= x) vec[id].eb (d[stk[l]].x), d[stk[l]].y = -1; else return ;
build ();
}
}
} bl[505];
void init () {
int B = sqrt (n);
m = n / B + (bool) (n % B);
rep (i, 1, m) {
bl[i].ld = bl[i - 1].rd + 1;
bl[i].rd = min (bl[i - 1].rd + B, n);
bl[i].build ();
}
}
signed main () {
// freopen ("1.in", "r", stdin);
// freopen ("1.out", "w", stdout);
n = rd (), q = rd ();
rep (i, 1, n) a[i] = rd (), d[i] = (Dot) {i, a[i]};
init ();
int now = 0;
rep (i, 1, q) {
g[i].opt = rd ();
if (g[i].opt == 1) {
g[i].l = rd ();
rep (j, 1, m) bl[j].del (now, i, g[i].l);
} else if (g[i].opt == 2) {
++ now;
} else g[i].l = rd (), g[i].r = rd ();
}
rep (i, 1, n) {
s.upd (i, i), t.upd (i, a[i]);
}
seg::clear ();
now = 0;
rep (i, 1, q) {
if (g[i].opt == 1) {
int pos = seg::find (1, 1, n, g[i].l);
if (pos) seg::modify (1, 1, n, pos, n, g[i].l);
for (auto p : vec[i]) {
s.upd (p, - p), t.upd (p, - a[p]);
seg::upd (1, 1, n, p, g[i].l);
}
} else {
if (g[i].opt == 2) {
++ now; seg::add (1, 1);
} else {
int l = g[i].l, r = g[i].r;
printf ("%lld\n", now * (s.qry (r) - s.qry (l - 1)) + t.qry (r) - t.qry (l - 1) + seg::qry (1, 1, n, l, r));
}
}
}
}