Description
共有m部电影,编号为1~m,第i部电影的好看值为w[i]。
在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部。
你可以选择l,r(1<=l<=r<=n),并观看第l,l+1,…,r天内所有的电影。如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值。所以你希望最大化观看且仅观看过一次的电影的好看值的总和。
Input
第一行两个整数n,m(1<=m<=n<=1000000)。
第二行包含n个整数f[1],f[2],…,f[n](1<=f[i]<=m)。
第三行包含m个整数w[1],w[2],…,w[m](1<=w[j]<=1000000)。
Output
输出观看且仅观看过一次的电影的好看值的总和的最大值。
Sample Input
9 4
2 3 1 1 4 1 2 4 1
5 3 6 6
Sample Output
15
样例解释:
观看第2,3,4,5,6,7天内放映的电影,其中看且仅看过一次的电影的编号为2,3,4。
枚举左端点
利用离线思想,l每往右1格,l——nxt[l]-1 就减去w[a[l]],nxt[l]——nxt[nxt[l]]加上w[a[l]],
注意边界
线段树维护即可
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
inline int read()
{
int ret=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9')
ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
return ret;
}
int n,m;
ll ans;
const int N=1e6+5;
int nxt[N],la[N],w[N],a[N];
ll tag[N<<2],c[N<<2];
inline void down(int p,int l,int r)
{
if(l<r)
{
int mid=(l+r)>>1;
tag[p<<1]+=tag[p],tag[(p<<1)|1]+=tag[p];
c[p<<1]+=tag[p],c[(p<<1)|1]+=tag[p];
}
tag[p]=0;
}
void add(int p,int l,int r,int x,int y,int k)
{
if(l==x&&r==y)
{
tag[p]+=k; c[p]+=k;
return;
}
down(p,l,r);
int mid=(l+r)>>1;
if(mid>=y) add(p<<1,l,mid,x,y,k);
else if(mid<x) add((p<<1)|1,mid+1,r,x,y,k);
else add(p<<1,l,mid,x,mid,k),
add((p<<1)|1,mid+1,r,mid+1,y,k);
c[p]=max(c[p<<1],c[(p<<1)|1]);
}
ll get(int p,int l,int r,int x,int y)
{
if(l==x&&r==y) return c[p];
down(p,l,r);
int mid=(l+r)>>1;
if(mid>=y) return get(p<<1,l,mid,x,y);
else if(mid<x) return get((p<<1)|1,mid+1,r,x,y);
else return max(get(p<<1,l,mid,x,mid),get((p<<1)|1,mid+1,r,mid+1,y));
}
int 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=n;i;i--)
nxt[i]=la[a[i]],
la[a[i]]=i;
for(int i=1;i<=m;i++)
if(la[i])
{
if(nxt[la[i]]) add(1,1,n,la[i],nxt[la[i]]-1,w[i]);
else add(1,1,n,la[i],n,w[i]);
}
ans=get(1,1,n,1,n);
for(int i=2;i<=n;i++)
{
if(nxt[i-1])
{
add(1,1,n,i-1,nxt[i-1]-1,-w[a[i-1]]);
if(nxt[nxt[i-1]]) add(1,1,n,nxt[i-1],nxt[nxt[i-1]]-1,w[a[i-1]]);
else add(1,1,n,nxt[i-1],n,w[a[i-1]]);
} else add(1,1,n,i-1,n,-w[a[i-1]]);
ans=max(ans,get(1,1,n,i,n));
}
printf("%lld\n",ans);
return 0;
}