BZOJ 3747 [POI2015]Kinoman

題目在這裏呀!

題意:

m部電影,n天放映,第i天放映第f[i]部電影,第i部電影的好看值爲w[i]。
一個區間[l,r],在第l天到第r天內,如果第i部電影只被看過一遍,那麼就有w[i]的貢獻,求最大貢獻。

題解:

感覺是一道好題哦~(5月份沒更過博啊終於打算寫幾篇了qwq)

從暴力入手吧,枚舉左端點l,向右掃,每次cnt[f[i]]++,如果此時cnt[f[i]]=1,則加上貢獻,如果cnt[f[i]]=2,則減去當前貢獻,去最大值。

那麼怎麼去優化它呢。我們可以考慮當左端點從l移動到l+1的時候,改變的貢獻。所以用tree[i]記錄l到i這段區間內的貢獻,放入線段樹中求最大值,現在就是要考慮如何修改了,我們用nxt[i]記錄從第i天往下下一個f[i]是第幾天。
所以當左端點移動時,cnt[f[l]]–,那麼tree[l+1…nxt[l]-1]-=w[f[l]],tree[nxt[l]…nxt[nxt[l]]-1]+=w[f[l]],在線段樹上區間修改即可。
好像沒什麼要多注意的?(我打這道題還算挺順利的吧

//Suplex
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 1001000
using namespace std;
int n,m,f[N],w[N],nxt[N],fr[N];
long long ans;

struct Segment{
    long long tag,val;
}t[N+N+N+N+N];

inline void pushdown(int p,int l,int r)
{
    if(l==r) return;
    t[p+p].tag+=t[p].tag;t[p+p+1].tag+=t[p].tag;
    t[p+p].val+=t[p].tag;t[p+p+1].val+=t[p].tag;
    t[p].tag=0;
}

void modify(int p,int l,int r,int x,int y,int delta)
{
    if(t[p].tag) pushdown(p,l,r);
    if(x<=l && r<=y){
        t[p].tag=delta;t[p].val+=delta;
        return;
    }
    int mid=(l+r)>>1;
    if(y<=mid) modify(p+p,l,mid,x,y,delta);
    else if(x>mid) modify(p+p+1,mid+1,r,x,y,delta);
    else modify(p+p,l,mid,x,mid,delta),modify(p+p+1,mid+1,r,mid+1,y,delta);
    t[p].val=max(t[p+p].val,t[p+p+1].val);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&f[i]);
    for(int i=1;i<=m;i++) scanf("%d",&w[i]);
    for(int i=n;i;i--){
        nxt[i]=fr[f[i]];
        fr[f[i]]=i;
    }
    for(int i=1;i<=m;i++)
         if(fr[i]){
             if(!nxt[fr[i]]) modify(1,1,n,fr[i],n,w[i]);
             else modify(1,1,n,fr[i],nxt[fr[i]]-1,w[i]);
         }
    for(int l=1;l<=n;l++){
        ans=max(ans,t[1].val);
        if(nxt[l]){
            modify(1,1,n,l,nxt[l]-1,-w[f[l]]);     
            if(nxt[nxt[l]]) modify(1,1,n,nxt[l],nxt[nxt[l]]-1,w[f[l]]);
            else modify(1,1,n,nxt[l],n,w[f[l]]);
        }
        else modify(1,1,n,l,n,-w[f[l]]);
    }
    printf("%lld\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章