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

  

posted @ 2016-01-21 13:08  wangyurzee  阅读(345)  评论(0编辑  收藏  举报