都说是经典题。嗯我也觉得是 然而我太菜了。。
一开始在想O(n)的做法 想不到 难道是nlogn?
看了看status个个都挺慢的啊 本来就是要nlogn。。
原来直接暴力上线段树搞就好了 (线段树维护这个点为起点到i的答案
p[i]表示上次这个数出现的时间 我们枚举右端点,每次加入一个数,那么p[i]+1到i这段位置的答案加上这个数的权值,p[p[i]]+1到p[i]这段位置的答案减去这个数的权值,然后查询[1,i]的最大值即可。
这次看来是打搓了。。跑的好慢啊QAQ
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1000002;
inline int read(){
char ch=getchar(); int x=0,f=1;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0'; ch=getchar();}
return x*f;
}
int a[N],w[N],p[N],z[N]; LL s[N<<2],lz[N<<2];
void pd(int x){
int lc=x<<1,rc=lc|1; LL u=lz[x]; lz[x]=0;
s[lc]+=u,lz[lc]+=u,s[rc]+=u,lz[rc]+=u;
}
void g(int x,int l,int r,int ql,int qr,int u){
if(ql>r || qr<l || ql>qr)return;
if(ql<=l&&r<=qr){lz[x]+=u,s[x]+=u; return;}
pd(x); int lc=x<<1,rc=lc|1,mid=(l+r)>>1;
g(lc,l,mid,ql,qr,u),g(rc,mid+1,r,ql,qr,u);
s[x]=max(s[lc],s[rc]);
}
LL c(int x,int l,int r,int ql,int qr){
if(ql>r || qr<l)return 0;
if(ql<=l&&r<=qr)return s[x];
pd(x); int lc=x<<1,rc=lc|1,mid=(l+r)>>1;
return max(c(lc,l,mid,ql,qr),c(rc,mid+1,r,ql,qr));
}
int main()
{
int n=read(),m=read(),i;
for(i=1;i<=n;i++)a[i]=read(),p[i]=z[a[i]],z[a[i]]=i;
for(i=1;i<=m;i++)w[i]=read();
LL ans=0;
for(i=1;i<=n;i++){
g(1,1,n,p[p[i]]+1,p[i],-w[a[i]]);
g(1,1,n,p[i]+1,i,w[a[i]]);
ans=max(c(1,1,n,1,i),ans);
}
printf("%lld\n",ans);
return 0;
}