1. 程式人生 > >BZOJ 3747: [POI2015]Kinoman(線段樹)

BZOJ 3747: [POI2015]Kinoman(線段樹)

傳送門

解題思路

  遇到這種選區間的題,很多時候都是列舉左端點,然後計算右端點。考慮列舉左端點之後如何維護,設下一部和\(i\)這個位置的電影相同的為\(nxt[i]\),那麼如果左端點從\(i\)移動到\(i+1\)\([i+1,nxt[i]-1]\)這段區間會減少\(w[f[i]]\),而\([nxt[i],nxt[nxt[i]]-1\)會增加\(w[f[i]]\),發現可以線段樹維護。

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>

using namespace std;
const int N=1000005;
typedef long long LL;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return f?x:-x;  
}

inline LL max(LL x,LL y){return x>y?x:y;}

int n,m,pre[N],w[N],nxt[N],cnt[N],f[N];
LL ans,Max[N<<2],tag[N<<2];

inline void pushdown(int x){
    Max[x<<1]+=tag[x];Max[x<<1|1]+=tag[x];
    tag[x<<1]+=tag[x];tag[x<<1|1]+=tag[x];
    tag[x]=0;   
}

void update(int x,int l,int r,int L,int R,LL k){
    if(L>R) return ;
    if(L<=l && r<=R) {Max[x]+=k;tag[x]+=k;return ;} 
    int mid=(l+r)>>1;if(tag[x]) pushdown(x);
    if(L<=mid) update(x<<1,l,mid,L,R,k);
    if(mid<R) update(x<<1|1,mid+1,r,L,R,k);
    Max[x]=max(Max[x<<1],Max[x<<1|1]);
}   

LL query(int x,int l,int r,int L,int R){
    if(L<=l && r<=R) return Max[x];
    int mid=(l+r)>>1;if(tag[x]) pushdown(x);    
    if(L>mid) return query(x<<1|1,mid+1,r,L,R);
    else if(R<=mid) return query(x<<1,l,mid,L,R);
    else return max(query(x<<1,l,mid,L,R),query(x<<1|1,mid+1,r,L,R));
}

signed main(){
    n=rd(),m=rd();int x;
    for(int i=1;i<=n;i++){
        x=rd();f[i]=x;
        if(pre[x]) nxt[pre[x]]=i;
        pre[x]=i;   
    }
    LL now=0;
    for(int i=1;i<=m;i++) w[i]=rd();
    for(int i=1;i<=n;i++){
        if(!cnt[f[i]]) now+=w[f[i]];
        else if(cnt[f[i]]==1) now-=w[f[i]];
        cnt[f[i]]++;update(1,1,n,i,i,now);
    }
    for(int i=1;i<=n;i++){
        ans=max(ans,query(1,1,n,i,n));
        if(!nxt[i]) update(1,1,n,i+1,n,-w[f[i]]);
        else update(1,1,n,i+1,nxt[i]-1,-w[f[i]]);
        if(nxt[i] && !nxt[nxt[i]]) update(1,1,n,nxt[i],n,w[f[i]]);
        else update(1,1,n,nxt[i],nxt[nxt[i]]-1,w[f[i]]);
    }
    printf("%lld\n",ans);
    return 0;
}