洛谷P3582 [POI2015] KIN

分析

我就简单口糊一下吧。

这题其实很像一个最大子段。

我们可以考虑用线段树维护区间最大子段和,不会的做这题

先枚举右端点,然后我们求的就是 [ 1 , r ] [1,r] [1,r] 中的最大价值。

我们假设 [ 1 , r − 1 ] [1,r-1] [1,r1] 已经消除了影响,可以直接求最大子段和。对于新碰到的电影编号 x x x,我们就要消除它的影响。

无非就是将上一个与 x x x 编号相同的位置(即第几天)上的价值改成负的,然后把上上个与 x x x 编号相同的位置上的价值改成0的(上上个前面相同编号位置的价值已经是0)。

这样就消除了影响,最后取max就可以了。

时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

Code(无read)

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1e6;
const ll inf = 1ll << 63;
ll ans = -inf;
int n, m, a[N|1], w[N|1], pre[N|1], lst[N|1];
struct SegamentTree {
	static const int MAX = N;
	struct TreeNode {
		ll val, lval, rval, sum;
	} tr[MAX<<2];
	inline TreeNode pushup(TreeNode ls, TreeNode rs) {
		TreeNode rt;
		rt.val = max(ls.val, max(rs.val, ls.rval+rs.lval));
		rt.lval = max(ls.lval, ls.sum+rs.lval);
		rt.rval = max(rs.rval, rs.sum+ls.rval);
		rt.sum = ls.sum + rs.sum;
		return rt;
	}
	void update(int k, int l, int r, int x, int t) {
		if(l == r) {
			tr[k] = {t, t, t, t};
			return;
		}
		int mid = l + (r - l >> 1);
		if(x <= mid) update(k<<1, l, mid, x, t);
		else update(k<<1|1, mid+1, r, x, t);
		tr[k] = pushup(tr[k<<1], tr[k<<1|1]);
	}
} A;
signed main() {
	n = read(), m = read();
	for(int i = 1; i <= n; ++i)
		a[i] = read();
	for(int i = 1; i <= m; i++)
		w[i] = read();
	for(int i = 1; i <= n; ++i) {
		pre[i] = lst[a[i]], lst[a[i]] = i;
		if(pre[i]) A.update(1, 1, n, pre[i], -w[a[i]]);
		if(pre[pre[i]]) A.update(1, 1, n, pre[pre[i]], 0);
		A.update(1, 1, n, i, w[a[i]]);
		ans = max(ans, A.tr[1].val);
	}
	printf("%lld", ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值