KTT
我们考虑传统的区间最大子段和方法,维护最大前后缀和 和最大子段和 ,这些东西直接区间加是不好维护的。但我们发现,设选择的长度是变量 ,区间加上的值为 ,这些东西都可以写成一个 的一次函数形式,考虑维护这些一次函数。
具体的,我们在每个节点维护一个阈值 ,表示要改变上述三个函数中任意一个所需要的最小增量。对于一次区间加操作,如果加数 就正常做,否则就暴力递归下去。
考虑 update 操作。对于 ,原始的更新式子是 ,我们将阈值设为这两个二次函数的交点,如果交点 或不存在则是 。对于 同理,三个取 min 即可得到阈值。
考虑看起来非常不对的时间复杂度:对于 ls 和 rs 的更新,显然每次只加正数时,它们的长度只会增加,复杂度 ,
对于 的更新,它有三种情况:左、右、左+右。设为 ,令当前节点选择的情况为 ,深度为 ,定义一个节点的势能为 ,对于一次暴力递归操作,一个节点的 一定会增大,势能减少了 ,而父亲至多只会增加 的势能。我们用 的时间是势能减少了至少 。
考虑总势能,初始有 的势能,一次修改会改 个节点,对于 会增加 的势能。对于前后缀和会增加 次,至多贡献 的势能。所以总势能是 的,我们用 的时间消耗掉一个势能,得到复杂度的一个上界是 。但是这个分析非常宽松,实际效率和 差不多。
#include <bits/stdc++.h>
const int N = 4e5 + 5;
using namespace std;
inline int read() {
register int s = 0, f = 1; register char ch = getchar();
while (!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
while (isdigit(ch)) s = (s * 10) + (ch & 15), ch = getchar();
return s * f;
}
typedef long long ll;
const ll inf = 1e16;
struct func {
int k; ll b;
inline func() { k = b = 0; }
inline func(int K, ll B) : k(K), b(B) { }
};
inline func operator + (func a, func b) {
return func(a.k + b.k, a.b + b.b);
}
inline pair<func, ll> calc(func a, func b) {
if (a.k < b.k || (a.k == b.k && a.b < b.b)) swap(a, b);
if (a.b >= b.b) return make_pair(a, inf);
return make_pair(b, (b.b - a.b) / (a.k - b.k));
}
struct node {
func ls, rs, mx, sum;
ll x;
};
inline node operator + (node a, node b) {
node res; pair<func, ll> t;
res.x = min(a.x, b.x);
t = calc(a.ls, a.sum + b.ls); res.ls = t.first; res.x = min(res.x, t.second);
t = calc(b.rs, a.rs + b.sum); res.rs = t.first; res.x = min(res.x, t.second);
t = calc(a.mx, b.mx); res.x = min(res.x, t.second);
t = calc(t.first, a.rs + b.ls); res.mx = t.first; res.x = min(res.x, t.second);
res.sum = a.sum + b.sum;
return res;
}
node p[N << 2];
ll tag[N << 2];
int n, q, a[N];
inline void update(int now) {
p[now] = p[now << 1] + p[now << 1 | 1];
}
inline void upd(int now, ll k) {
tag[now] += k;
p[now].x -= k;
p[now].ls.b += k * p[now].ls.k;
p[now].rs.b += k * p[now].rs.k;
p[now].mx.b += k * p[now].mx.k;
p[now].sum.b += k * p[now].sum.k;
}
inline void pushdown(int now) {
if (tag[now]) {
upd(now << 1, tag[now]);
upd(now << 1 | 1, tag[now]);
tag[now] = 0;
}
}
inline void build(int now, int l, int r) {
if (l >= r) {
p[now].ls = p[now].rs = p[now].mx = p[now].sum = func(1, a[l]);
p[now].x = inf; return ;
} int mid = l + r >> 1;
build(now << 1, l, mid); build(now << 1 | 1, mid + 1, r);
update(now);
}
inline void modify(int now, int l, int r, int ql, int qr, ll k) {
if (ql <= l && r <= qr) {
if (k > p[now].x) {
int mid = l + r >> 1;
k += tag[now]; tag[now] = 0;
modify(now << 1, l, mid, ql, qr, k);
modify(now << 1 | 1, mid + 1, r, ql, qr, k);
update(now);
} else upd(now, k);
return ;
} pushdown(now); int mid = l + r >> 1;
if (ql <= mid) modify(now << 1, l, mid, ql, qr, k);
if (qr > mid) modify(now << 1 | 1, mid + 1, r, ql, qr, k);
update(now);
}
inline node query(int now, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return p[now];
pushdown(now); int mid = l + r >> 1;
if (qr <= mid) return query(now << 1, l, mid, ql, qr);
if (ql > mid) return query(now << 1 | 1, mid + 1, r, ql, qr);
return query(now << 1, l, mid, ql, qr) + query(now << 1 | 1, mid + 1, r, ql, qr);
}
int main() {
n = read(); q = read();
for (int i = 1; i <= n; ++i) a[i] = read();
build(1, 1, n); int op, l, r, k;
while (q--) {
op = read(); l = read(); r = read();
if (op == 1) {
k = read();
modify(1, 1, n, l, r, k);
} else {
node t = query(1, 1, n, l, r);
printf("%lld\n", max(0ll, t.mx.b));
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App