[POI 2015]Kinoman

Posted NaVi_Awson

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[POI 2015]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

Hint

观看第2,3,4,5,6,7天内放映的电影,其中看且仅看过一次的电影的编号为2,3,4。

题解

这道题稀里糊涂的写了一个下午,思路什么的乱七八糟的...回家理清思路,半个小时就写完了。

我们枚举区间左端点,线段树维护每个位置作为右端点的答案,

$nex[i]$记录第$i$天的电影下次播放时间

当我们往左移的时候,显然$i$这个点的颜色已经不会为之后的区间有加成,我们需要将$i$~$nex[i]-1$这一段区间减掉$w[f[i]]$。

同样,当我们左端点左移的时候,将迎接一个新的$f[i]$,那么我们就要将$nex[i]$~$nex[nex[i]]-1$这一段区间加上$w[f[i]]$。

线段树维护,支持区间修改以及查询最大值。

注意一开始的时候就把所有颜色的最左的一段加入线段树中。

 1 //It is made by Awson on 2017.10.16
 2 #include <set>
 3 #include <map>
 4 #include <cmath>
 5 #include <ctime>
 6 #include <cmath>
 7 #include <stack>
 8 #include <queue>
 9 #include <vector>
10 #include <string>
11 #include <cstdio>
12 #include <cstdlib>
13 #include <cstring>
14 #include <iostream>
15 #include <algorithm>
16 #define LL long long
17 #define Min(a, b) ((a) < (b) ? (a) : (b))
18 #define Max(a, b) ((a) > (b) ? (a) : (b))
19 #define sqr(x) ((x)*(x))
20 #define Lr(o) (o<<1)
21 #define Rr(o) (o<<1|1)
22 using namespace std;
23 const int N = 1000000;
24 void read(int &x) {
25     char ch; bool flag = 0;
26     for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == -)) || 1); ch = getchar());
27     for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
28     x *= 1-2*flag;
29 }
30 
31 struct segment {
32     LL sgm[(N<<2)+5], lazy[(N<<2)+5];
33     void pushdown(int o) {
34         sgm[Lr(o)] += lazy[o], sgm[Rr(o)] += lazy[o];
35         lazy[Lr(o)] += lazy[o], lazy[Rr(o)] += lazy[o];
36         lazy[o] = 0;
37     }
38     void update(int o, int l, int r, int a, int b, int key) {
39         if (a <= l && r <= b) {
40             sgm[o] += key, lazy[o] += key;
41             return;
42         }
43         pushdown(o);
44         int mid = (l+r)>>1;
45         if (a <= mid) update(Lr(o), l, mid, a, b, key);
46         if (b > mid) update(Rr(o), mid+1, r, a, b, key);
47         sgm[o] = Max(sgm[Lr(o)], sgm[Rr(o)]);
48     }
49 }T;
50 
51 int n, m, f[N+5], w[N+5];
52 int path[N+5], nex[N+5];
53 
54 void work() {
55     read(n), read(m);
56     for (int i = 1; i <= n; i++) read(f[i]);
57     for (int i = 1; i <= m; i++) read(w[i]);
58     for (int i = n; i >= 1; i--) {
59         nex[i] = path[f[i]], path[f[i]] = i;
60     }
61     for (int i = 1; i <= m; i++) if (path[i]) {
62         if (nex[path[i]]) T.update(1, 1, n, path[i], nex[path[i]]-1, w[i]);
63         else T.update(1, 1, n, path[i], n, w[i]);
64     }
65     LL ans = 0;
66     for (int i = 1; i <= n; i++) {
67         ans = Max(ans, T.sgm[1]);
68         if (nex[i]) {
69             T.update(1, 1, n, i, nex[i]-1, -w[f[i]]);
70             if (nex[nex[i]]) T.update(1, 1, n, nex[i], nex[nex[i]]-1, w[f[i]]);
71             else T.update(1, 1, n, nex[i], n, w[f[i]]);
72         }else T.update(1, 1, n, i, n, -w[f[i]]);
73     }
74     printf("%lld\n", ans);
75 }
76 int main() {
77     work();
78     return 0;
79 }

 

以上是关于[POI 2015]Kinoman的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3747: [POI2015]Kinoman

[POI2015]Kinoman

bzoj3747[POI2015]Kinoman

BZOJ 3747 3747: [POI2015]Kinoman (线段树)

@bzoj - 3747@ [POI2015] Kinoman

bzoj3747: [POI2015]Kinoman