BZOJ3747:[POI2015]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。

Solution

记一个数组$pre[i]$,表示$i$这个位置上的数上一次出现的位置在哪。

从左往右扫一边,区间$pre[i]+1$到$i$加上当前数的权值,$pre[pre[i]]+1$到$pre[i]$这段位置减去这个数的权值。然后查询区间$[1,i]$,取查询的$max$即为答案。

Code

 1 #include<iostream>
 2 #include<cstdio>
 3 #define N (1000009)
 4 #define LL long long
 5 using namespace std;
 6 
 7 struct Sgt{LL max,add;}Segt[N<<2];
 8 int n,m,f[N],w[N],pre[N],a[N];
 9 LL ans;
10 
11 void Pushdown(int now)
12 {
13     Segt[now<<1].add+=Segt[now].add;
14     Segt[now<<1].max+=Segt[now].add;
15     Segt[now<<1|1].add+=Segt[now].add;
16     Segt[now<<1|1].max+=Segt[now].add;
17     Segt[now].add=0;
18 }
19 
20 void Update(int now,int l,int r,int l1,int r1,int k)
21 {
22     if (l>r1 || r<l1) return;
23     if (l1<=l && r<=r1) 
24     {
25         Segt[now].add+=k;
26         Segt[now].max+=k;
27         return;
28     }
29     Pushdown(now);
30     int mid=(l+r)>>1;
31     Update(now<<1,l,mid,l1,r1,k);
32     Update(now<<1|1,mid+1,r,l1,r1,k);
33     Segt[now].max=max(Segt[now<<1].max,Segt[now<<1|1].max);
34 }
35 
36 LL Query(int now,int l,int r,int l1,int r1)
37 {
38     if (l>r1 || r<l1) return -1;
39     if (l1<=l && r<=r1) return Segt[now].max;
40     Pushdown(now);
41     int mid=(l+r)>>1;
42     return max(Query(now<<1,l,mid,l1,r1),Query(now<<1|1,mid+1,r,l1,r1));
43 }
44 
45 int main()
46 {
47     scanf("%d%d",&n,&m);
48     for (int i=1; i<=n; ++i)
49         scanf("%d",&f[i]), pre[i]=a[f[i]], a[f[i]]=i;
50     for (int i=1; i<=m; ++i)
51         scanf("%d",&w[i]);
52     for (int i=1; i<=n; ++i)
53     {
54         Update(1,1,n,pre[i]+1,i,w[f[i]]);
55         Update(1,1,n,pre[pre[i]]+1,pre[i],-w[f[i]]);
56         ans=max(ans,Query(1,1,n,1,i));
57     }
58     printf("%lld\n",ans);
59 }
posted @ 2018-12-02 14:20  Refun  阅读(175)  评论(0编辑  收藏  举报