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);
}


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