[POI2015] KIN/Kinoman ——线段树入门

[POI2015] KIN

题目描述

共有 \(m\) 部电影,编号为 \(1,2,\ldots,m\),第 \(i\) 部电影的好看值为 \(w_i\)

\(n\) 天之中,每天会放映一部电影,第 \(i\) 天放映的是第 \(f_i\) 部。

你可以选择 \(l,r\)\(1\le l\le r\le n\)),并观看第 \(l,l+1,\ldots,r\) 天内所有的电影。

但如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值。

现在,您需要最大化观看且仅观看过一次的电影的好看值的总和。

输入格式

第一行两个整数 \(n,m\)

第二行包含 \(n\) 个整数,第 \(i\) 个表示 \(f_i\)

第三行包含 \(m\) 个整数,第 \(i\) 个表示 \(w_i\)

输出格式

一行一个整数,表示仅观看过一次的电影的好看值的总和的最大值。

样例 #1

样例输入 #1

9 4
2 3 1 1 4 1 2 4 1
5 3 6 6

样例输出 #1

15

提示

【数据范围】

对于 \(100\%\) 的数据,\(1\le m\le n\le 10^6\)\(1\le f_i\le m\)\(1\le w_i\le 10^6\)


原题名称:Kinoman。

分析

对于每种电影只有最后两处有用。在最后一处打上正标记,倒数第二处打上负标记,求最大右区间和即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+100;
int n,m,g[N],lef[N];
long long val[N],all,ans;
int tot[N],rec[N],num[N];
int pos[N][2];
struct segtree
{
    long long val;
    long long rsum;
}s[N<<2];
void pushup(segtree &t,segtree &a,segtree &b)//cong you kai shi de zui da qu jian he
{
    t.val=a.val+b.val;
    t.rsum=max( b.rsum,b.val+a.rsum );
}
void upd(int i,int l,int r,int x,long long z)
{
    if(l==r)
    {
        s[i].rsum=s[i].val=z;
        return ;
    }
    int mid=(l+r)>>1;
    if(x<=mid)upd(i<<1,l,mid,x,z);
    else upd(i<<1|1,mid+1,r,x,z);
    pushup(s[i],s[i<<1],s[i<<1|1]);
}
inline void eq(segtree &a,long long b,long long c)
{
    a.val=b;
    a.rsum=c;
}
segtree que(int i,int l,int r,int x,int y)//query [x,y]
{
    if(l>=x && r<=y)
        return s[i];
    int mid=(l+r)>>1;
    segtree lc,rc,nw;
    eq(lc,0,0);eq(rc,0,0);eq(nw,0,0);
    if(x<=mid)lc=que(i<<1,l,mid,x,y);
    if(y>mid)rc=que(i<<1|1,mid+1,r,x,y);
    pushup(nw,lc,rc);
    return nw;
}
void work()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%d",&g[i]);
    for(int i=1;i<=m;++i){scanf("%lld",&val[i]);all+=val[i];}
    for(int i=1;i<=n;++i)//record the last two g[i]
    {
        //rec[ 1 ~ m ]
        lef[i]=rec[g[i]];
        ++num[g[i]];
        long long v=val[g[i]];
        if(num[g[i]]==1)
        {
            pos[g[i]][0]=i;
            upd(1,1,n,i,v);
        }
        else if(num[g[i]]==2)
        {
            upd(1,1,n,pos[g[i]][0],-v);
            pos[g[i]][1]=i;
            upd(1,1,n,i,v);
        }
        else
        {
            upd(1,1,n,pos[g[i]][0],0);
            pos[g[i]][0]=pos[g[i]][1];
            upd(1,1,n,pos[g[i]][1],-v);
            pos[g[i]][1]=i;
            upd(1,1,n,i,v);
        }
        segtree node=que(1,1,n,lef[i]+1,i);
        ans=max(ans,node.rsum);
        rec[g[i]]=i;
    }
    cout<<ans;
}
int main()
{
    work();
    return 0;
}























posted @ 2024-10-28 22:06  Glowingfire  阅读(6)  评论(0编辑  收藏  举报