题目链接
题解
维护pre[i],为i节点前一个与它相同的点的位置
固定右端点,向左计算,得到区间内的价值最大字段,怎么计算呢,钦定这个点一定只看一遍,那么区间pre[i] + 1到i的总价值直接加上i的价值
那么我们就只需要在pre[i]到pre[pre[i]]这段区间减掉这个值了, 因为在 per[pre[i]]之前的已经被减掉了
那么,线段树区间修改+维护最大值
代码
/*
维护pre[i],为i节点前一个与它相同的点的位置
固定右端点,向左计算,得到价值最大区间,怎么计算呢,钦定这个点一定只看一遍,那么区间pre[i] + 1到i的总价值直接加上i的价值
那么我们就只需要在pre[i]到pre[pre[i]]这段区间减掉这个值了, 因为在 per[pre[i]]之前的已经被减掉了
那么,线段树区间修改+维护最大值
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
inline int read() {
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c <= '9' && c >= '0')x = x * 10 + c- '0',c = getchar(); return x;
}
int n,m;
const int maxn = 1000007;
int a[maxn],val[maxn],last[maxn],pre[maxn];
LL tree[maxn << 2] ,tag[maxn << 2];
void update(int x) {
tree[x] = std::max(tree[x << 1],tree[x << 1 | 1]);
}
void pushdown(int x) {
if(!tag[x])return;
tag[x << 1] += tag[x];tag[x << 1 | 1] += tag[x];
tree[x << 1] += tag[x];
tree[x << 1 | 1] += tag[x];
tag[x] = 0;
}
void add(int x,int l,int r,int tl,int tr,int w) {
if(l >= tl && r <= tr) {
tag[x] += w; tree[x] += w; return ;
}
int mid = l + r >> 1;
pushdown(x);
if(tl <= mid) add(x << 1,l,mid,tl,tr,w);
if(tr > mid) add(x << 1 | 1,mid + 1,r,tl,tr,w);
update(x);
}
int main() {
n = read(),m = read();
for(int i = 1;i <= n;++ i) a[i] = read();
for(int i = 1;i <= m;++ i) val[i] = read();
for(int i = 1;i <= n;++ i) {
pre[i] = last[a[i]],
last[a[i]] = i;
}
LL ans = 0;
for(int i = 1;i <= n;++ i) {
add(1,1,n,pre[i] + 1,i,val[a[i]]);
if(pre[i]) add(1,1,n,pre[pre[i]] + 1,pre[i],-val[a[i]]);
ans = std::max(ans,tree[1]);
}
printf("%lld
",ans);
return 0;
}