• [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
    ", ans);
    75 }
    76 int main() {
    77     work();
    78     return 0;
    79 }
  • 相关阅读:
    内容敏感图像压缩
    线性筛素数
    一元三次方程
    holiday
    电话网络
    expect之初使用
    python基本数据类型
    Linux系统中的日志管理
    Linux计划任务(at,crontab)
    RHEL7 启动配置 加密
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7679152.html
Copyright © 2020-2023  润新知