NKOJ3772 看电影
时间限制 : - MS 空间限制 : 165536 KB
评测说明 : 1000ms
问题描述
共有m部电影,编号为1~m,第i部电影的好看值为w[i]。
在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部。
你可以选择l,r(1<=l<=r<=n),并观看第l,l+1,…,r天内所有的电影。如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值。所以你希望最大化观看且仅观看过一次的电影的好看值的总和。
输入格式
第一行两个整数n,m(1<=m<=n<=1000000)。
第二行包含n个整数f[1],f[2],…,fn。
第三行包含m个整数w[1],w[2],…,wm。
输出格式
输出观看且仅观看过一次的电影的好看值的总和的最大值。
样例输入
9 4
2 3 1 1 4 1 2 4 1
5 3 6 6
样例输出
15
提示
样例解释:
观看第2,3,4,5,6,7天内放映的电影,其中看且仅看过一次的电影的编号为2,3,4。
思路:
先处理从第一部看到第i部的好看值,然后依次讨论不看第1部、不看第2部…..的情况.
维护一颗线段树,每个叶节点j储存不看1~i部时看[i+1,j]部时的权值。
处理一个next[i]表示i号下一个和他同一部电影的编号。
每次少看第i部,则[i+1,next[i]-1]的每个点权值都减小这部电影的权值,[next[i],next[next[i]]-1]的每个点权值增加。
特别的,如果没有next[i],需要需要修改后面所有点的权值
#include<cstdio>
#include<iostream>
using namespace std;
const int need=1000003;
#define ls s<<1
#define rs (s<<1)|1
int ww[need],h[need],vistime[need],ne[need],fi[need];
int a[need];
//.......................................................
inline void in_(int &d)
{
char t=getchar();
while(t<'0'||t>'9') t=getchar();
for(d=0;t<='9'&&t>='0';t=getchar()) d=(d<<1)+(d<<3)+t-'0';
}
//.......................................................
struct fy
{
int a,b,val,lazy;
} w[need<<3];
void NBHB(int s)
{
w[s].val=max(w[ls].val,w[rs].val);
}
void build(int s,int l,int r)
{
w[s].a=l,w[s].b=r;
if(l==r)
{
w[s].val=a[l];
return ;
}
build(ls,l,(l+r)>>1);
build(rs,(l+r)/2+1,r);
NBHB(s);
}
int x,y,v;
void putdown(int s)
{
w[ls].val+=w[s].lazy;
w[rs].val+=w[s].lazy;
if(w[s].a==w[s].b) return ;
w[ls].lazy+=w[s].lazy;
w[rs].lazy+=w[s].lazy;
w[s].lazy=0;
}
void change(int s)
{
if(x>w[s].b||y<w[s].a) return ;
if(w[s].lazy!=0) putdown(s);
if(w[s].a==w[s].b)
{
w[s].val+=v;
return ;
}
if(x<=w[s].a&&w[s].b<=y)
{
w[s].val+=v;
w[s].lazy=v;
return ;
}
change(ls),change(rs);
NBHB(s);
}
//.......................................................
int main()
{
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) in_(h[i]);
for(int i=n;i>=1;i--) //处理next
{
ne[i]=fi[h[i]];
fi[h[i]]=i;
}
for(int i=1;i<=m;i++) in_(ww[i]);
int ans=0;
for(int i=1;i<=n;i++) //处理[1,i]
{
if(vistime[h[i]]==0) a[i]=a[i-1]+ww[h[i]],vistime[h[i]]++;
else if(vistime[h[i]]==1) a[i]=a[i-1]-ww[h[i]],vistime[h[i]]++;
else a[i]=a[i-1];
ans=max(ans,a[i]);
if(ne[i]==0) ne[i]=n+1;//如果后面没有,需要将后面所有数修改
}
build(1,1,n);
for(int i=1;i<=n;i++)
{
x=i+1,y=ne[i]-1,v=-ww[h[i]];
if(x<=y) change(1);
x=ne[i],y=ne[ne[i]]-1,v=ww[h[i]];
if(x<=y) change(1);
ans=max(ans,w[1].val);
}
printf("%d",ans);
}