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天内所有的电影。如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值。所以你希望最大化观看且仅观看过一次的电影的好看值的总和。
 
 
题解
    令llas[i]表示第i号颜色上上一次出现的位置,类似地,las[i]表示第i号颜色上一次出现的位置。
    考虑枚举终点r,那么假设第r天的电影种类为i,那么若l<=las[i],这个r对应的l就无法获得w[i]。
    那么算法就很显然了,考虑线段树维护,对于每一个r,在线段树上【llas[i]+1,las[i]】上减去w[i],在【las[i]+1,r】上加上w[i]。r对应的答案即【1,r】的最大值。
    时间复杂度O(nlogn)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2000005;
inline int read(){
    int f=1,x=0; char ch;
    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;
} 
int c[N*2],n,m,a[N],b[N],llas[N],las[N];
struct Tre{
    #define ls p*2
    #define rs p*2+1
    ll a[N*2+1],tag[N*2+1];
    void update(int p){
        a[p]=max(a[ls],a[rs]);
    }
    void down(int p,int l,int r){
        int mid=(l+r)>>1;
        a[ls]+=tag[p];
        a[rs]+=tag[p];
        tag[ls]+=tag[p]; tag[rs]+=tag[p];
        tag[p]=0;
    }
    void modify(int p,int l,int r,int ql,int qr,ll x){
        if (ql<=l&&qr>=r){a[p]+=x; tag[p]+=x; return;}
        int mid=(l+r)>>1;
        down(p,l,r);
        if (ql<=mid) modify(ls,l,mid,ql,qr,x);
        if (qr>mid) modify(rs,mid+1,r,ql,qr,x);
        update(p);
    }
    ll query(int p,int l,int r,int ql,int qr){
        if (ql<=l&&qr>=r){ return a[p];}
        ll ans=0; int mid=(l+r)>>1;
        down(p,l,r);
        if (ql<=mid) ans=max(ans,query(ls,l,mid,ql,qr));
        if (qr>mid) ans=max(ans,query(rs,mid+1,r,ql,qr));
        return ans;
    }
}t;
int main(){
    n=read(),m=read();
    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=1;i<=m;i++) b[i]=read();
    long long ans=0;
        for (int i=1;i<=n;i++) {
            if (llas[a[i]]+1<=las[a[i]]) t.modify(1,1,n,llas[a[i]]+1,las[a[i]],-b[a[i]]);
            t.modify(1,1,n,las[a[i]]+1,i,b[a[i]]);
            long long p=t.query(1,1,n,1,i);
            if (p>ans) ans=p;
            llas[a[i]]=las[a[i]];
            las[a[i]]=i;
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

 

posted @ 2020-10-22 08:54  Cardinal  阅读(60)  评论(0)    收藏  举报