将序列分块后面对每一个序列维护一个李超线段树

操作一:整块的用李超线段树求,残余的暴力搞。

操作二:因为 \(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;
}