Bzoj3747 [POI1015] Kinoman

 

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。

 

Bzoj权限题。只过了样例,尚未评测。

题面搬运自神犇hzwer博客。

 

 

线段树维护区间最值,枚举区间起点,不断把起点前面的电影贡献值删去,再把当前电影“从当前直到它下次出现之前”的区间都新加上当前电影的贡献值,不断更新最大答案。

刚开始按区间加法写的,所以变量用了sum,写到一半发现只搞区间最大值就好,然而懒得改变量名了……

 

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #define ls l,mid,rt<<1
 7 #define rs mid+1,r,rt<<1|1
 8 #define LL long long
 9 using namespace std;
10 const int mxn=1000010;
11 int n,m;
12 int f[mxn],w[mxn];
13 int next[mxn],last[mxn];
14 int cnt[mxn];
15 struct node{
16     LL sum;//变量名是sum,实际是存区间最大值 
17     LL tag;
18 }t[mxn<<2];
19 void Build(int l,int r,int rt){//init //实际并没有用到 
20     if(l==r){
21         t[rt].sum=t[rt].tag=0;
22         return;
23     }
24     int mid=(l+r)>>1;
25     Build(ls);Build(rs);
26     return;
27 }
28 void pushdown(int l,int r,int rt){
29     if(l==r)return;
30     if(t[rt].tag){ 
31         int mid=(l+r)>>1;
32         t[rt<<1].tag+=t[rt].tag;
33         t[rt<<1|1].tag+=t[rt].tag;
34         t[rt<<1].sum+=t[rt].tag;
35         t[rt<<1|1].sum+=t[rt].tag;
36         t[rt].tag=0;
37     }
38 }
39 void add(int L,int R,int v,int l,int r,int rt){
40     if(t[rt].tag)pushdown(l,r,rt);
41     if(L<=l && r<=R){
42         t[rt].tag+=v;
43         t[rt].sum+=v;
44         return;
45     }
46     int mid=(l+r)>>1;
47     if(L<=mid)add(L,R,v,ls);
48     if(R>mid)add(L,R,v,rs);
49     t[rt].sum=max(t[rt<<1].sum,t[rt<<1|1].sum);
50     return;
51 }
52 void read(){
53     scanf("%d%d",&n,&m);
54     int i,j;
55     for(i=1;i<=n;i++)scanf("%d",&f[i]);
56     for(i=1;i<=m;i++)scanf("%d",&w[i]);
57     return;
58 }
59 int main(){
60     read();
61     int i,j;
62     for(i=n;i;i--){
63         next[i]=last[f[i]];
64         last[f[i]]=i;
65     }
66     for(i=1;i<=m;i++){
67         if(last[i]){
68             if(!next[last[i]])add(last[i],n,w[i],1,n,1); 
69             else add(last[i],next[last[i]]-1,w[i],1,n,1);
70         }
71     }
72     LL ans=0;
73     for(i=1;i<=n;i++){
74         ans=max(ans,t[1].sum);
75         int tmp=next[i];
76         if(tmp){
77             add(i,tmp-1,-w[f[i]],1,n,1);
78             if(next[tmp])add(tmp,next[tmp]-1,w[f[i]],1,n,1); 
79             else add(tmp,n,w[f[i]],1,n,1);//如果之后没有相同电影了,从next[i]到n的区间都加值 
80         }
81         else add(i,n,-w[f[i]],1,n,1);//删除上一个区间的值 
82     }
83     printf("%lld",ans);
84     return 0;
85 }

 

posted @ 2016-09-05 23:33  SilverNebula  阅读(318)  评论(0编辑  收藏  举报
AmazingCounters.com