zoukankan      html  css  js  c++  java
  • 【BZOJ-3747】Kinoman 线段树

    3747: [POI2015]Kinoman

    Time Limit: 60 Sec  Memory Limit: 128 MB
    Submit: 715  Solved: 294
    [Submit][Status][Discuss]

    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。

    HINT

    Source

    鸣谢Jcvb

    Solution

    经典题,然而想了一会.

    我们先预处理出$suf[i]$表示$i$这个位置放的电影,和它同样的电影下一次放的位置。

    然后我们枚举左端点,不断更新答案就行。

    Code

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define LL long long
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f; 
    }
    #define MAXN 1000100
    int N,M;
    namespace SegmentTree
    {
        struct SegmentTreeNode{int l,r; LL tag,maxx;}tree[MAXN<<2];
        #define ls now<<1
        #define rs now<<1|1
        inline void Update(int now) {tree[now].maxx=max(tree[ls].maxx,tree[rs].maxx);}
        inline void PushDown(int now)
        {
            if (tree[now].l==tree[now].r || !tree[now].tag) return;
            LL D=tree[now].tag; tree[now].tag=0;
            tree[ls].maxx+=D; tree[ls].tag+=D;
            tree[rs].maxx+=D; tree[rs].tag+=D;
        }
        inline void BuildTree(int now,int l,int r)
        {
            tree[now].l=l; tree[now].r=r;
            if (l==r) return;
            int mid=(l+r)>>1;
            BuildTree(ls,l,mid); BuildTree(rs,mid+1,r);
            Update(now);
        }
        inline void Modify(int now,int L,int R,int D)
        {
            if (L>R) return;
            int l=tree[now].l,r=tree[now].r;
            PushDown(now);
            if (L<=l && R>=r) {tree[now].maxx+=D; tree[now].tag+=D; return;}
            int mid=(l+r)>>1;
            if (L<=mid) Modify(ls,L,R,D);
            if (R>mid) Modify(rs,L,R,D);
            Update(now);
        }
    }dddddd
    int suf[MAXN],last[MAXN],f[MAXN],w[MAXN],first[MAXN];
    LL ans;
    int main()
    {
        N=read(),M=read();
        for (int i=1; i<=N; i++) f[i]=read();
        for (int i=1; i<=M; i++) w[i]=read();
        for (int i=1; i<=N; i++)
            suf[last[f[i]]]=i,last[f[i]]=i;
        for (int i=1; i<=N; i++) 
            if (!first[f[i]]) first[f[i]]=i;
        SegmentTree::BuildTree(1,1,N);
        for (int i=1; i<=M; i++)
            if (first[i])
                SegmentTree::Modify(1,first[i],suf[first[i]]? suf[first[i]]-1:N,w[i]);
        for (int i=1; i<=N; i++)
            {
                ans=max(ans,SegmentTree::tree[1].maxx);
                SegmentTree::Modify(1,i,suf[i]? suf[i]-1:N,-w[f[i]]);
                if (suf[i]) SegmentTree::Modify(1,suf[i],suf[suf[i]]? suf[suf[i]]-1:N,w[f[i]]); else continue;
            }
        printf("%lld
    ",ans);
        return 0;
    }

    经典题我居然现在才做....

  • 相关阅读:
    前端学PHP之错误处理
    mysql数据库学习目录
    前端学数据库之存储
    前端学数据库之函数
    用shell脚本监控进程是否存在 不存在则启动的实例
    在notepad++里面使用正则表达式替换掉所有行逗号前面内容
    mysql合并 两个count语句一次性输出结果的方法
    硬件中断和DPC一直占40-52%左右 解决方法
    解决secureCRT 数据库里没有找到防火墙 '无' 此会话降尝试不通过防火墙进行连接。
    Java eclipse下 Ant build.xml实例详解 附完整项目源码
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5928802.html
Copyright © 2011-2022 走看看