3747: [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天内所有的电影。如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值。所以你希望最大化观看且仅观看过一次的电影的好看值的总和。

题解:

先预处理出对于每个节点,下一个跟他相同颜色的点的位置
然后枚举最后选的那个区间的左端点r,用一颗线段树记录对于每个r,这个区间的得分是多少。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int N=1000005;
int n,m;
int last[N],nex[N];
int a[N],val[N];
struct node{
    ll mx,lazy;
    int l,r;
}tr[4000005];
void bt(int x,int l,int r)
{
    tr[x].l=l;
    tr[x].r=r;
    tr[x].mx=tr[x].lazy=0;
    int mid=(l+r)>>1;
    if(l<r)
    {
        bt(x<<1,l,mid);
        bt(x<<1|1,mid+1,r);
    }
}
void update(int k)
{
    int l=tr[k].l,r=tr[k].r;
    if (l==r) return;
    ll lazy=tr[k].lazy; tr[k].lazy=0;
    tr[k<<1].lazy+=lazy; tr[k<<1|1].lazy+=lazy;
    tr[k<<1].mx+=lazy; tr[k<<1|1].mx+=lazy;
}
void change(int rt,int l,int r,int l1,int r1,int c)
{
    if(tr[rt].lazy) update(rt);
    if(l==l1&&r==r1){tr[rt].mx+=c;tr[rt].lazy+=c;return;}
    int mid=(l+r)>>1;
    if(r1<=mid) change(rt<<1,l,mid,l1,r1,c);
    else if(l1>mid) change(rt<<1|1,mid+1,r,l1,r1,c);
    else change(rt<<1,l,mid,l1,mid,c),change(rt<<1|1,mid+1,r,mid+1,r1,c);
    tr[rt].mx=max(tr[rt<<1].mx,tr[rt<<1|1].mx);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    memset(last,0,sizeof(last));
    memset(nex,0,sizeof(nex));
    for(int i=n;i>=1;i--)
    {
        nex[i]=last[a[i]];
        last[a[i]]=i;
    }
    bt(1,1,n);
    for(int j=1;j<=m;j++) 
    {
        scanf("%d",&val[j]);
        if(last[j])
        {
            if(!nex[last[j]]) change(1,1,n,last[j],n,val[j]);
           else change(1,1,n,last[j],nex[last[j]]-1,val[j]);
        }
         
    }
     
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        ans=max(ans,tr[1].mx);
        if(nex[i])
        {
            change(1,1,n,i,nex[i]-1,-val[a[i]]);
            if(nex[nex[i]]) change(1,1,n,nex[i],nex[nex[i]]-1,val[a[i]]);
            else change(1,1,n,nex[i],n,val[a[i]]);
        }
        else change(1,1,n,i,n,-val[a[i]]);
    }
    printf("%lld\n",ans);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章