BZOJ3747: [POI2015]Kinoman
3747: [POI2015]Kinoman
Time Limit: 60 Sec Memory Limit: 128 MBSubmit: 991 Solved: 425
[Submit][Status][Discuss]
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
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。
思路{
和HH的项链树状数组做法的思想类似.
有重复的颜色记录出$ Nxt [ i ] $为下一个和$ i $ 颜色相同的位置.
那么从左往右扫区间右端点,相当于一个取$ Max $的操作.用线段树维护.
考虑更改,删除当前点{
删除区间[ i , Nxt [ i ] ] 贡献,
新增区间 [ Nxt [ i ] ,Nxt [ i ] ] 贡献
}
用线段树搞就可以了.
}
#include<bits/stdc++.h> #define il inline #define RG register #define ll long long #define db double #define N 1000010 using namespace std; int w[N],f[N],n,m,last[N],nxt[N],fir[N]; namespace Tree{ ll Max[N*4],lazy[N*4]; #define rs ((o<<1)|1) #define ls (o<<1) #define mid ((l+r)>>1) void up(int o){ Max[o]=max(Max[rs],Max[ls]); } void down(int o){ if(lazy[o]){ Max[rs]+=lazy[o];lazy[rs]+=lazy[o]; Max[ls]+=lazy[o];lazy[ls]+=lazy[o]; lazy[o]=0; } } void Insert(int o,int l,int r,int L,int R,ll num){ if(l!=r)down(o); if(l>=L&&r<=R){Max[o]+=num,lazy[o]+=num;return;} if(mid<L)Insert(rs,mid+1,r,L,R,num); else if(mid>=R)Insert(ls,l,mid,L,R,num); else Insert(rs,mid+1,r,mid+1,R,num),Insert(ls,l,mid,L,mid,num); up(o); } ll Query(int o,int l,int r,int L,int R){ if(l!=r)down(o); if(l>=L&&r<=R)return Max[o]; if(mid<L)return Query(rs,mid+1,r,L,R); else if(mid>=R)return Query(ls,l,mid,L,R); else return max(Query(rs,mid+1,r,L,R),Query(ls,l,mid,L,R)); } } int main(){ scanf("%d%d",&n,&m);for(int i=1;i<=n;++i)scanf("%d",&f[i]); for(int i=1;i<=m;++i)scanf("%d",&w[i]); for(int i=1;i<=n;++i){ if(last[f[i]])nxt[last[f[i]]]=i; last[f[i]]=i; } memset(last,0,sizeof(last)); for(int i=n;i;i--){ if(last[f[i]])fir[last[f[i]]]=i; last[f[i]]=i; } for(int i=1;i<=n;++i) if(!fir[i]){ if(nxt[i])Tree::Insert(1,1,n,i,nxt[i]-1,w[f[i]]); else Tree::Insert(1,1,n,i,n,w[f[i]]); } ll Ans(0); for(int i=1;i<=n;++i){ Ans=max(Ans,Tree::Query(1,1,n,i,n)); if(nxt[i]){ Tree::Insert(1,1,n,i,nxt[i]-1,-w[f[i]]); if(nxt[nxt[i]])Tree::Insert(1,1,n,nxt[i],nxt[nxt[i]]-1,w[f[i]]); else Tree::Insert(1,1,n,nxt[i],n,w[f[i]]); } else Tree::Insert(1,1,n,i,n,-w[f[i]]); }cout<<Ans; return 0; }