【线段树】loj_3264. 「ROIR 2020 Day 2」海报
题意
\(n\)个人排成一个圆,每个人有一个价值,不能同时选择4个或以上相邻的人。
求选择的价值最大。
还有\(q\)次修改,每次修改一个人的价值。
对于\(100\%\)的数据,有\(4\leq n\leq 40000, 0\leq a_i, v_i\leq 10^9, 1\leq p_i\leq n, 0\leq q\leq 40000\)。
思路
先看成序列上的问题,设\(f_{i,j}\)为前面选择i个人后面选择j个人的最大价值。
那么圆上的问题可以通过枚举来解决。
如何求出\(f\)?
可利用线段树,在每次上传操作中更新区间的\(f\)。
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#define int long long
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
const int inf = 2100000000, MAXN = 40001;
int n;
int a[MAXN];
int dat[MAXN << 2][4][4];
inline int read() {
int res = 0, f = 1;
char c = getchar();
while (!isdigit(c)) {
if (c == '-') f = -1;
c = getchar();
}
while (isdigit(c))
res = res * 10 + (c ^ 48), c = getchar();
return res * f;
}
void update(int p, int len1, int len2) {//注意分类讨论
memset(dat[p], 0, sizeof(dat[p]));
int x = p << 1, y = p << 1 | 1;
for (int i = 0; i <= 3; ++i)
for (int j = 0; j <= 3; ++j)
if (i + j < len1)
for (int pp = 0; pp <= 3 - j; ++pp)
for (int q = 0; q <= 3; ++q)
if (pp + q < len2)
dat[p][i][q] = std::max(dat[p][i][q], dat[x][i][j] + dat[y][pp][q]);
if (len1 <= 3)
for (int i = 0; i <= 3 - len1; ++i)
for (int j = 0; j <= 3; ++j)
if (i + j < len2)
dat[p][i + len1][j] = std::max(dat[p][i + len1][j], dat[x][len1][len1] + dat[y][i][j]);
if (len2 <= 3)
for (int i = 0; i <= 3; ++i)
for (int j = 0; j <= 3 - len2; ++j)
if (i + j < len1)
dat[p][i][j + len2] = std::max(dat[p][i][j + len2], dat[x][i][j] + dat[y][len2][len2]);
if (len1 + len2 <= 3)
dat[p][len1 + len2][len1 + len2] = std::max(dat[p][len1 + len2][len1 + len2], dat[x][len1][len1] + dat[y][len2][len2]);
}
void build(int p, int l, int r) {
if (l == r) {
dat[p][1][1] = a[l];
return;
}
int mid = l + r >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
update(p, mid - l + 1, r - mid);
}
void modify(int p, int l, int r, int pos, int val) {
if (l == r) {
dat[p][1][1] = val;
return;
}
int mid = l + r >> 1;
if (pos <= mid)
modify(p << 1, l, mid, pos, val);
else
modify(p << 1 | 1, mid + 1, r, pos, val);
update(p, mid - l + 1, r - mid);
}
int query() {
int res = 0;
for (int i = 0; i <= 3; i++)
for (int j = 0; j <= 3 - i; j++)
res = std::max(res, dat[1][i][j]);
return res;
}
signed main() {
n = read();
for (int i = 1; i <= n; i++)
a[i] = read();
build(1, 1, n);
printf("%lld\n", query());
int q = read(), x, y;
while (q--) {
x = read(), y = read();
modify(1, 1, n, x, y);
printf("%lld\n", query());
}
}

浙公网安备 33010602011771号