将序列分块后面对每一个序列维护一个李超线段树
操作一:整块的用李超线段树求,残余的暴力搞。
操作二:因为 \(v\) 是正数,所以直接加入一条新的线段就能覆盖掉原来的线段。
操作三:整块的用 \(tag\) 标记维护,残块的直接覆盖掉。
注意题面中说操作一和操作三不会超过 \(10^5\),复杂度有保证。
#include<iostream>
#include<cstdio>
#include<cmath>
#define LL long long
using namespace std;
int n, m, siz, opt, l, r, x, y;
LL ans;
const int N = 200010;
int id[N], lp[1010], rp[1010];
LL k[N], b[N], tag[N];
inline int read()
{
int res = 0; char ch = getchar(); bool XX = false;
for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
return XX ? -res : res;
}
struct Tree
{
#define lson (rt<<1)
#define rson ((rt<<1)|1)
struct xian {LL k, b;} li[4200];
inline LL val(int x, LL k, LL b) {return k * x + b;}
void change(int rt, int l, int r, int k, int b)
{
if (l == r)
{
if (val(l, k, b) >= val(l, li[rt].k, li[rt].b))li[rt].k = k, li[rt].b = b;
return;
}
int mid = (l + r) >> 1;
if (val(mid , k , b) <= val(mid , li[rt].k , li[rt].b))
{
if (val(l , k , b) < val(l , li[rt].k , li[rt].b)) change(rson , mid + 1 , r , k , b);
else change(lson , l , mid , k , b);
}
else
{
if (val(l , k , b) < val(l , li[rt].k , li[rt].b)) change(lson , l , mid , li[rt].k , li[rt].b);
else change(rson , mid + 1 , r , li[rt].k , li[rt].b);
li[rt].k = k; li[rt].b = b;
}
}
LL ask(int rt, int l, int r, int pos)
{
if (l == r)return val(pos, li[rt].k, li[rt].b);
int mid = (l + r) >> 1;
return max(val(pos, li[rt].k, li[rt].b), pos <= mid ? ask(lson, l, mid, pos) : ask(rson, mid + 1, r, pos));
}
} S[510];
LL solve(int l, int r, int x)
{
LL ans = 0;
for (int i = l; i <= r; ++i)ans = max(ans, k[i] * x + b[i] + tag[id[i]]);
return ans;
}
void build(int x)
{
for (int i = lp[x]; i <= rp[x]; ++i)S[x].change(1, 1, 1000, k[i], b[i]);
}
signed main()
{
cin >> n >> m; siz = sqrt(n);
for (int i = 1; i <= n; ++i)k[i] = read();
for (int i = 1; i <= n; ++i)b[i] = read();
for (int i = 1; i <= n; ++i)
{
id[i] = (i - 1) / siz + 1;
if (!lp[id[i]])lp[id[i]] = i;
rp[id[i]] = i;
}
for (int i = 1; i <= id[n]; ++i)build(i);
while (m--)
{
opt = read();
if (opt == 1)
{
l = read(); r = read(); x = read();
if (id[l] == id[r])printf("%lld\n", solve(l, r, x));
else
{
ans = max(solve(l, rp[id[l]], x), solve(lp[id[r]], r, x));
for (int i = id[l] + 1; i <= id[r] - 1; ++i)
ans = max(ans, S[i].ask(1, 1, 1000, x) + tag[i]);
printf("%lld\n", ans);
}
}
else if (opt == 2)
{
x = read(); y = read(); k[x] += y;
S[id[x]].change(1, 1, 1000, k[x], b[x]);
}
else if (opt == 3)
{
l = read(); r = read(); x = read();
if (id[l] == id[r])
{
for (int i = l; i <= r; ++i)b[i] += x;
build(id[l]);
}
else
{
for (int i = l; i <= rp[id[l]]; ++i)b[i] += x, S[id[l]].change(1, 1, 1000, k[i], b[i]);
for (int i = id[l] + 1; i <= id[r] - 1; ++i)tag[i] += x;
for (int i = lp[id[r]]; i <= r; ++i)b[i] += x, S[id[r]].change(1, 1, 1000, k[i], b[i]);
}
}
}
return 0;
}