bzoj3747: [POI2015]Kinoman
从左到右枚举左端点,用线段树维护每个右端点的愉♂悦值
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <algorithm> #define ll long long #define N 1000006 using namespace std; inline int read(){ int ret=0;char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while ('0'<=ch&&ch<='9'){ ret=ret*10-48+ch; ch=getchar(); } return ret; } int n; struct STnode{ int l,r; ll maxv; ll tag; }; struct SegmentTree{ STnode t[4*N]; void PushUp(int x){t[x].maxv=max(t[x<<1].maxv,t[x<<1^1].maxv);} void PushDown(int x){ if (t[x].l==t[x].r) t[x].tag=0; if (!t[x].tag) return; t[x<<1].maxv+=t[x].tag; t[x<<1].tag+=t[x].tag; t[x<<1^1].maxv+=t[x].tag; t[x<<1^1].tag+=t[x].tag; t[x].tag=0; } void build(int x,int l,int r){ t[x].l=l;t[x].r=r;t[x].tag=0; if (l==r){t[x].maxv=0;return;} int mid=(l+r)/2; build(x<<1,l,mid); build(x<<1^1,mid+1,r); PushUp(x); } void modify(int x,int l,int r,int delta){ PushDown(x); if (l<=t[x].l&&t[x].r<=r){ t[x].maxv+=delta; t[x].tag+=delta; return; } int mid=(t[x].l+t[x].r)/2; if (l<=mid) modify(x<<1,l,r,delta); if (r>mid) modify(x<<1^1,l,r,delta); PushUp(x); } ll getans(){return t[1].maxv;} } st; int a[N],next[N],film,value[N]; int now[N]; int main(){ n=read();film=read(); for (int i=1;i<=n;++i) a[i]=read(); for (int i=1;i<=film;now[i++]=n+1) value[i]=read(); for (int i=n;i;--i){ next[i]=now[a[i]]; now[a[i]]=i; } st.build(1,1,n); for (int i=1;i<=film;++i) st.modify(1,now[i],next[now[i]]-1,value[i]); ll ans=0; for (int i=1;i<=n;++i){ ans=max(ans,st.getans()); st.modify(1,i,next[i]-1,-value[a[i]]); if (next[i]<=n) st.modify(1,next[i],next[next[i]]-1,value[a[i]]); } printf("%lld\n",ans); return 0; }