【线段树】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());
	}
}
posted @ 2021-07-20 09:41  nymph181  阅读(84)  评论(0)    收藏  举报