1.思路
对于此类问题,我们采用枚举右端点的方法来求解,当要添加第i天所要看的电影时,那么从上一次出现f[i]电影的地方pre[i]+1到第i天,我们加上好看值w[f[i]], 同时从pre[pre[i]]+1到pre[i], 因为存在重复,所以我们减去w[f[i]],然后求区间的最大值.
2.代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
#define ls rt<<1
#define rs rt<<1|1
typedef long long ll;
int f[N], w[N];
int pre[N], suf[N];
ll add[N<<2], v[N<<2];
inline void pushUp(int rt) {
v[rt] = v[ls] > v[rs]? v[ls] : v[rs];
}
void pushDown(int rt) {
if(add[rt]) {
add[ls] += add[rt];
add[rs] += add[rt];
v[ls] += add[rt];
v[rs] += add[rt];
add[rt] = 0;
}
}
void update(int rt, int l, int r, int a, int b, int c) {
if(a <= l && r <= b) {
v[rt] += (ll)c;
add[rt] += (ll)c;
return ;
}
int mid = (l + r) >> 1;
pushDown(rt);
if(a <= mid) {
update(ls, l, mid, a, b, c);
}
if(b > mid) {
update(rs, mid+1, r, a, b, c);
}
pushUp(rt);
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++ i) {
scanf("%d", &f[i]);
}
for(int i = 1; i <= m; ++ i) {
scanf("%d", &w[i]);
}
for(int i = 1; i <= n; ++ i) {
pre[i] = suf[f[i]];
suf[f[i]] = i;
}
// 枚举右端点
ll res = 0;
for(int i = 1; i <= n; ++ i) {
if(pre[i]) {
update(1, 1, n, pre[pre[i]]+1, pre[i], -w[f[i]]);
}
update(1, 1, n, pre[i]+1, i, w[f[i]]);
res = max(res, v[1]);
}
printf("%lld\n", res);
return 0;
}