CF722C Destroying Array 题解
根据目前作者了解,本题有两种解法:并查集/线段树。
1. 并查集
对于并查集这种只能合并不能删除的数据结构,当然要想一点珂技。
我们倒过来思考,将删除操作变为插入操作,相邻点合并。
考虑到序列里面的数都为正数,那么直接取出子树权值和最大的即可。
预计时间复杂度 \(O(n)\),上界 \(O(n \log n)\)。
2. 线段树
这个需要模仿 GSS 系列,维护前缀和,后缀和,总和,最大子段和,然后删除操作处理成最小值。这个方法支持数为负数的情况。
没了解过 GSS 系列的读者可以看一看这篇文章:数据结构专题-专项训练:线段树2(GSS1-5)
时间复杂度 \(O(n \log n)\),上下界也为 \(O(n \log n)\)。
代码:(只有线段树)
#include <bits/stdc++.h>
#define Max(a, b) ((a > b) ? a : b)
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
const LL inf = -1e14;
int n, a[MAXN];
struct node
{
int l, r, flag;
LL sum, pre, aft, maxn;
#define l(p) tree[p].l
#define r(p) tree[p].r
#define s(p) tree[p].sum
#define p(p) tree[p].pre
#define a(p) tree[p].aft
#define m(p) tree[p].maxn
node operator +(const node &fir)
{
node sec;
sec.l = l; sec.r = fir.r;
sec.sum = sum + fir.sum;
sec.pre = Max(pre, sum + fir.pre);
sec.aft = Max(fir.aft, fir.sum + aft);
sec.maxn = Max(fir.maxn, Max(maxn, aft + fir.pre));
sec.flag = flag | fir.flag;
return sec;
}
}tree[MAXN << 2];
int read()
{
int sum = 0, fh = 1; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') fh = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {sum = (sum << 3) + (sum << 1) + (ch ^ 48); ch = getchar();}
return sum * fh;
}
void build(int p, int l, int r)
{
l(p) = l, r(p) = r;
if (l == r) {s(p) = a(p) = p(p) = m(p) = a[l]; tree[p].flag = 1; return ;}
int mid = (l + r) >> 1;
build (p << 1, l, mid); build(p << 1 | 1, mid + 1, r);
tree[p] = tree[p << 1] + tree[p << 1 | 1];
}
void deal(int p, int x)
{
if (l(p) == r(p) && r(p) == x)
{
tree[p].flag = 0;
s(p) = m(p) = a(p) = p(p) = inf;
return ;
}
int mid = (l(p) + r(p)) >> 1;
if (x <= mid) deal(p << 1, x);
else deal(p << 1 | 1, x);
tree[p] = tree[p << 1] + tree[p << 1 | 1];
}
int main()
{
n = read();
for (int i = 1; i <= n; ++i) a[i] = read();
build(1, 1, n);
for (int i = 1; i <= n; ++i)
{
int x = read();
deal(1, x);
printf("%lld\n", Max(0ll, tree[1].maxn));
}
return 0;
}