• 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
    ",ans);
    59 }
  • 相关阅读:
    linux自动清理30天之前的文件
    Oracle树查询及相关函数
    jackson循环引用导致序列化stackOverFlow的解决
    java核心技术36讲笔记
    Quartz学习
    Quartz学习
    java核心技术36讲
    git常用命令
    CTCall简介(后续会继续补充)
    自定义导航栏,隐藏导航栏底部的灰色线条
  • 原文地址:https://www.cnblogs.com/refun/p/10053245.html
Copyright © 2020-2023  润新知