专栏文章
题解:CF1787I Treasure Hunt
CF1787I题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minpmkin
- 此快照首次捕获于
- 2025/12/02 06:17 3 个月前
- 此快照最后确认于
- 2025/12/02 06:17 3 个月前
注意到该和式即求最大的 之和加上 之和使得 。我们希望 与 无关,这样就是最大前缀和加上最大子段和(注意均可以取 )。我们注意到当 取得最大子段和时,如果 ,使 显然更优,于是最大前缀和的 一定不属于 ,直接考虑最大子段和加上最大前缀和即可。
我们考虑倒着加入数。设当前考虑了 的后缀, 的最大前缀和为 ,最大子段和为 。因为较大的 的答案严格包含较小的 ,所以 均单调不降。我们考量加入 后有怎样的变化。对于任意 ,显然有 ,我们在线段树上将 区间加 ,随后线段树上二分最小的小于 的位置 ,将 区间赋值为 即可。
我们记 表示 的最大子段和的左端点,,显然 是单调不降的, 是单调不升的。在加入 时,如果 ,那么我们将 显然不劣,而由单调性我们知道这样的 一定是一段区间,我们使用单调栈维护 即可。因为一些 增加了,所以对于一些 ,可能 。因为 单调不降,满足该条件的 仍然是一段区间,我们考虑每个变化的 ,线段树上二分最大的 使 ,区间修改 即可。同时,如果 ,我们将 不劣,而这样的 依然是一个区间,线段树上二分做区间覆盖即可。
综上,我们完整地解决了以上问题,时间复杂度 。注意本题稍微卡常。
Code:
CPP#include<bits/stdc++.h>
#define mem(a, v) memset(a, v, sizeof(a))
#pragma GCC optimize ("Ofast")
using namespace std;
namespace IO{
#define SIZ (1 << 18)
char ibuf[SIZ], *p1 = nullptr, *p2 = nullptr;
#define gc() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, SIZ, stdin), p1 == p2) ? EOF : *p1++)
template <typename tp>
void rd(tp &x){
x = 0;
int f = 1;
char c = gc();
for (;!isdigit(c); c == '-' && (f = -1), c = gc());
for (;isdigit(c); x = x * 10 + (c ^ 48), c = gc());
x *= f;
}
template <typename tp, typename... Arg>
inline void rd(tp &x, Arg &...args){
rd(x), rd(args...);
}
char obuf[SIZ], *p3 = obuf;
inline void flush(){
fwrite(obuf, 1, p3 - obuf, stdout), p3 = obuf;
}
inline void pc(const char c){
p3 - obuf == SIZ && (flush(), 1538), *p3++ = c;
}
template <typename tp>
void prt(tp x, char ed = '\n'){
x < 0 && (pc('-'), x = -x);
static char stk[40];
int stkp = 0;
do{
stk[stkp] = char(x % 10), x /= 10, ++stkp;
} while (x);
while (stkp){
pc(char(stk[--stkp] + '0'));
}
pc(ed);
}
#undef gc
#undef SIZ
}
using namespace IO;
const int maxn = 1e6 + 5, mod = 998244353;
struct Val{
int l, r;
long long val;
constexpr Val(int l = 0, int r = 0, long long val = 0): l(l), r(r), val(val){}
} stk[maxn];
int t, n, tot, res;
int a[maxn];
long long pre[maxn];
pair<int, int> tmp[maxn];
template<typename Tp_x, typename Tp_y>
inline int mod_add(Tp_x x, Tp_y y){
return x += y, x >= mod ? x -= mod : x;
}
template<typename Tp_x, typename Tp_y>
inline int self_mod_add(Tp_x &x, Tp_y y){
return x = mod_add(x, y);
}
template<typename Tp, typename... Arg>
inline int mod_add(Tp x, Arg ...args){
return x += mod_add(args...), x >= mod ? x -= mod : x;
}
namespace segtree{
struct{
long long mn, modi, sum, add;
} tree[maxn << 2];
inline void pushup(int index){
tree[index].sum = tree[index << 1].sum + tree[index << 1 | 1].sum, tree[index].mn = min(tree[index << 1].mn, tree[index << 1 | 1].mn);
}
inline void _modi(int index, int L, int R, long long k){
tree[index].sum = (R - L + 1) * k, tree[index].mn = tree[index].modi = k, tree[index].add = 0;
}
inline void _add(int index, int L, int R, long long k){
tree[index].sum += (R - L + 1) * k, tree[index].mn += k, tree[index].add += k;
}
inline void pushdown(int index, int L, int R){
const int mid = L + R >> 1;
tree[index].modi < 1e18 && (_modi(index << 1, L, mid, tree[index].modi), _modi(index << 1 | 1, mid + 1, R, tree[index].modi), tree[index].modi = 1e18);
_add(index << 1, L, mid, tree[index].add), _add(index << 1 | 1, mid + 1, R, tree[index].add), tree[index].add = 0;
}
inline void modify(int index, int L, int R, int l, int r, long long k){
if (l <= L && r >= R){
return _modi(index, L, R, k);
}
pushdown(index, L, R);
const int mid = L + R >> 1;
l <= mid && (modify(index << 1, L, mid, l, r, k), 1538), r > mid && (modify(index << 1 | 1, mid + 1, R, l, r, k), 1538), pushup(index);
}
inline void add(int index, int L, int R, int l, int r, long long k){
if (l <= L && r >= R){
return _add(index, L, R, k);
}
pushdown(index, L, R);
const int mid = L + R >> 1;
l <= mid && (add(index << 1, L, mid, l, r, k), 1538), r > mid && (add(index << 1 | 1, mid + 1, R, l, r, k), 1538), pushup(index);
}
inline long long query(int index, int L, int R, int l, int r){
if (l <= L && r >= R){
return tree[index].sum;
}
pushdown(index, L, R);
const int mid = L + R >> 1;
long long res = 0;
l <= mid && (res += query(index << 1, L, mid, l, r)), r > mid && (res += query(index << 1 | 1, mid + 1, R, l, r));
return res;
}
inline int fnd(int index, int L, int R, long long x){
if (L == R){
return L;
}
pushdown(index, L, R);
const int mid = L + R >> 1;
return tree[index << 1 | 1].mn <= x ? fnd(index << 1 | 1, mid + 1, R, x) : fnd(index << 1, L, mid, x);
}
}
using namespace segtree;
int main(){
rd(t);
while (t--){
rd(n), tot = res = 0;
for (int i = 1; i <= n << 2; i++){
tree[i].sum = tree[i].add = 0, tree[i].mn = -1e18, tree[i].modi = 1e18;
}
for (int i = 1; i <= n; i++){
rd(a[i]), pre[i] = pre[i - 1] + a[i];
}
for (int i = n; i; i--){
int top = 0;
while (tot && stk[tot].val > pre[i - 1]){
add(1, 1, n, stk[tot].l, stk[tot].r, stk[tot].val - pre[i - 1]), tmp[++top] = make_pair(stk[tot].l, stk[tot].r), tot--;
}
int L = n, R = 0;
for (int j = top; j; j--){
const long long l = tmp[j].first, r = tmp[j].second, v = query(1, 1, n, r, r), pos = fnd(1, 1, n, v);
pos > r && (modify(1, 1, n, r + 1, pos, v), 1538), L = min(L, int(l)), R = max(R, int(pos));
}
const int pos = fnd(1, 1, n, max(0, a[i]));
modify(1, 1, n, i, pos, max(0, a[i])), L = min(L, i), R = max(R, pos);
if (L <= R){
for (;tot && stk[tot].r <= R; tot--);
tot && (stk[tot].l = max(stk[tot].l, R + 1)), stk[++tot] = Val(L, R, pre[i - 1]);
}
self_mod_add(res, (query(1, 1, n, i, n) % mod + mod) % mod);
}
for (int i = 1; i <= n << 2; i++){
tree[i].sum = tree[i].add = 0, tree[i].mn = -1e18, tree[i].modi = 1e18;
}
for (int i = n; i; i--){
i < n && (add(1, 1, n, i + 1, n, a[i]), 1538);
const int pos = fnd(1, 1, n, max(0, a[i]));
modify(1, 1, n, i, pos, max(0, a[i])), self_mod_add(res, (query(1, 1, n, i, n) % mod + mod) % mod);
}
prt(res);
}
flush();
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...