发现每种电影只在两场之间产生贡献(只有$pos$的一场的就在$[pos,n]$产生贡献)。那么我们针对每个位置$i$求出这场电影下一次出现的位置$nxt[i]$,然后每次更新一下,求整个区间的最大值。具体说来我们先在每个电影第一次上映的位置$i$对$[i,nxt[i]-1]$区间修改一下,然后从左到右扫过去,每次消除$[i,nxt[i]-1]$的贡献,再增加$[nxt[i],nxt[nxt[i]]-1]$的贡献即可。
注意:不一定每种电影都出现过!
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=1000005; 6 long long maxx[4*N],laz[4*N],ans; 7 int num[N],val[N],fir[N],las[N],nxt[N],n,m,rr; 8 void release(int nde) 9 { 10 if(laz[nde]) 11 { 12 int ls=2*nde,rs=2*nde+1; 13 laz[ls]+=laz[nde],laz[rs]+=laz[nde]; 14 maxx[ls]+=laz[nde],maxx[rs]+=laz[nde]; 15 laz[nde]=0; 16 } 17 } 18 void add(int nde,int l,int r,int nl,int nr,int task) 19 { 20 if(l>nr||r<nl) 21 return ; 22 else if(l>=nl&&r<=nr) 23 maxx[nde]+=task,laz[nde]+=task; 24 else 25 { 26 int mid=(l+r)/2,ls=2*nde,rs=2*nde+1; release(nde); 27 add(ls,l,mid,nl,nr,task),add(rs,mid+1,r,nl,nr,task); 28 maxx[nde]=max(maxx[ls],maxx[rs]); 29 } 30 } 31 long long query(int nde,int l,int r,int nl,int nr) 32 { 33 if(l>nr||r<nl) 34 return 0; 35 else if(l>=nl&&r<=nr) 36 return maxx[nde]; 37 else 38 { 39 int mid=(l+r)/2,ls=2*nde,rs=2*nde+1; release(nde); 40 return max(query(ls,l,mid,nl,nr),query(rs,mid+1,r,nl,nr)); 41 } 42 } 43 int main () 44 { 45 scanf("%d%d",&n,&m); 46 for(int i=1;i<=n;i++) 47 { 48 scanf("%d",&num[i]); 49 if(las[num[i]]) 50 nxt[las[num[i]]]=i; 51 las[num[i]]=i; 52 } 53 for(int i=n;i;i--) 54 fir[num[i]]=i; 55 for(int i=1;i<=m;i++) 56 scanf("%d",&val[i]); 57 for(int i=1;i<=m;i++) 58 if(fir[i]) 59 { 60 rr=nxt[fir[i]]?nxt[fir[i]]-1:n; 61 add(1,1,n,fir[i],rr,val[i]); 62 } 63 for(int i=1;i<=n;i++) 64 { 65 ans=max(ans,maxx[1]); 66 rr=nxt[i]?nxt[i]-1:n; 67 add(1,1,n,i,rr,-val[num[i]]); 68 if(nxt[i]) 69 { 70 rr=nxt[nxt[i]]?nxt[nxt[i]]-1:n; 71 add(1,1,n,nxt[i],rr,val[num[i]]); 72 } 73 } 74 printf("%lld",ans); 75 return 0; 76 }