BZOJ 3747 Kinoman 发表于 2017-03-07 | 更新于 2018-06-18 LinkSolution比较常见的技巧吧。 枚举右端点,在线段树的每个节点ppp维护序列中点ppp到右端点的和,然后就是一个区间修改和区间查询了。 Code123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130#include "lucida"const int MAXN=1000000+11;using std::max;namespace _SegTree_ { const int SIZE=MAXN<<2; struct Node { Node *son[2]; int64 maxv,add; Node(); void Down(); void Up(); void Add(int64); void *operator new(size_t); }*null=new Node; Node::Node(){ maxv=add=0; son[0]=son[1]=null; } void *Node::operator new(size_t) { static Node *Pool=(Node*)malloc(SIZE*sizeof(Node)),*Me=Pool; return Me++; } void Node::Down() { if(add) { son[0]->Add(add); son[1]->Add(add); add=0; } } void Node::Up() { maxv=max(son[0]->maxv,son[1]->maxv); } void Node::Add(int64 adv) { if(this==null) return; add+=adv; maxv+=adv; } struct SegTree { Node *root;int L,R; SegTree(){} SegTree(int,int); void Build(Node*&,int,int); void Edit(Node*,int,int,int,int,int64); void Edit(int,int,int64); int64 Access(Node*,int,int,int,int); int64 Access(int,int); }; SegTree::SegTree(int L,int R):L(L),R(R) { root=null; Build(root,L,R); } void SegTree::Build(Node *&pos,int L,int R) { pos=new Node; if(L!=R) { int Mid=(L+R)>>1; Build(pos->son[0],L,Mid); Build(pos->son[1],Mid+1,R); } } void SegTree::Edit(Node *pos,int L,int R,int l,int r,int64 add) { if(L==l && R==r) pos->Add(add); else { int Mid=(L+R)>>1; pos->Down(); if(r<=Mid) Edit(pos->son[0],L,Mid,l,r,add); else if(Mid+1<=l) Edit(pos->son[1],Mid+1,R,l,r,add); else { Edit(pos->son[0],L,Mid,l,Mid,add); Edit(pos->son[1],Mid+1,R,Mid+1,r,add); } pos->Up(); } } void SegTree::Edit(int l,int r,int64 add) { if(!l || !r || l>r) return; Edit(root,L,R,l,r,add); } int64 SegTree::Access(Node *pos,int L,int R,int l,int r) { if(L==l && R==r) return pos->maxv; else { int Mid=(L+R)>>1; pos->Down(); if(r<=Mid) return Access(pos->son[0],L,Mid,l,r); else if(Mid+1<=l) return Access(pos->son[1],Mid+1,R,l,r); else return max(Access(pos->son[0],L,Mid,l,Mid),Access(pos->son[1],Mid+1,R,Mid+1,r)); } } int64 SegTree::Access(int l,int r) { return Access(root,L,R,l,r); }}using _SegTree_::SegTree;int main() {// freopen("input","r",stdin); static int movie[MAXN],w[MAXN]; int n,m;is>>n>>m; for(int i=1;i<=n;++i) is>>movie[i]; for(int i=1;i<=m;++i) is>>w[i]; SegTree seg(1,n); static int next[MAXN],pre[MAXN],now[MAXN]; for(int i=1;i<=n;++i) { pre[i]=now[movie[i]]; next[now[movie[i]]]=i; now[movie[i]]=i; //pre[i]=pre[i]?pre[i]:1; } for(int i=1;i<=m;++i) next[now[i]]=n+1;//now[m]... int64 Ans=0; for(int i=1;i<=n;++i) { int mv=movie[i]; //seg.Edit(pre[i],i-1,-w[mv]); //seg.Edit(i,next[i]-1,w[mv]); seg.Edit(pre[pre[i]]+1,pre[i],-w[mv]); seg.Edit(pre[i]+1,i,w[mv]); chkmx(Ans,seg.Access(1,i)); } os<<Ans<<'\n'; return 0;}