给定一个序列,查询区间子段去除重复元素的和的最大值。即给x,y,求sum=a[i]+a[i+1]+...+a[j],x<=i<=j<=y的最大的sum,但如果其中a[p]==a[q],i<=p<=q<=j,则计算和的时候a[p]和a[q]只计算一次。
这道题看起来和GSS1相似,但是做法完全不同。
使用数组lx[i]记录a[i]左边第一个等于a[i]的元素的位置+1。
离线处理所有的询问,将其按照右端点排序。
从左向右扫描数列,当扫描到a[i]时,线段树中第j个节点记录从j到i的去除重复元素的和,以及从j到i的区间子段去除重复元素的和的最大值。
即每扫描到一个新的数a[i],令数列b[lx[i]], b[lx[i]+1], ... , b[i]加上a[i],用线段树记录b[i]的区间历史最大值。
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
#include <iostream>
using namespace std;
struct Query {
int l,r,i;
friend bool operator < (const Query &a,const Query &b) {
return a.r<b.r;
}
};
struct SegNode {
SegNode *ls,*rs;
long long maxv,permaxv,maxlazy,lazy;
void down() {
if (ls) {
ls->maxlazy=max(ls->maxlazy,ls->lazy+maxlazy);
ls->lazy+=lazy;
}
if (rs) {
rs->maxlazy=max(rs->maxlazy,rs->lazy+maxlazy);
rs->lazy+=lazy;
}
permaxv=max(permaxv,maxv+maxlazy);
maxv+=lazy;
lazy=maxlazy=0;
}
void repair() {
ls->down();rs->down();
maxv=max(ls->maxv,rs->maxv);
permaxv=max(ls->permaxv,rs->permaxv);
maxlazy=lazy=0;
}
};
SegNode node[200000];
SegNode *root,*an;
void print() {
for (SegNode *i=node;i!=an;i++) {
printf("Node %d:\n",(int)(i-node));
printf(" ls:%d rs:%d\n",(int)(i->ls-node),(int)(i->rs-node));
printf(" maxv:%lld permaxv:%lld lazy:%lld maxlazy:%lld\n",i->maxv,i->permaxv,i->lazy,i->maxlazy);
}
printf("\n");
}
SegNode *maketree(int l,int r) {
SegNode *ans=an++;
if (l==r) {
ans->ls=ans->rs=NULL;
} else {
int t=(l+r)/2;
ans->ls=maketree(l,t);
ans->rs=maketree(t+1,r);
}
ans->maxlazy=ans->lazy=0;
ans->maxv=ans->permaxv=0;
return ans;
}
void set(SegNode *from,int l,int r,int ll,int rr,int x) {
//printf("%d %d %d %d\n",(int)(from-node),ll,rr,x);
from->down();
if (l==ll&&r==rr) {
from->lazy=x;
from->maxlazy=max(x,0);
} else {
int t=(l+r)/2;
if (rr<=t) {
set(from->ls,l,t,ll,rr,x);
} else if (ll>t) {
set(from->rs,t+1,r,ll,rr,x);
} else {
set(from->ls,l,t,ll,t,x);
set(from->rs,t+1,r,t+1,rr,x);
}
from->repair();
}
}
int get(SegNode *from,int l,int r,int ll,int rr) {
from->down();
if (l==ll&&r==rr) return from->permaxv;
int t=(l+r)/2;
if (rr<=t)
return get(from->ls,l,t,ll,rr);
else if (ll>t)
return get(from->rs,t+1,r,ll,rr);
else
return max(get(from->ls,l,t,ll,t),get(from->rs,t+1,r,t+1,rr));
}
map<int,int>last;
int n;
int a[100001];
int lx[100001];
Query b[100000];
int ans[100000];
int main() {
int i,x;
scanf("%d",&n);
for (i=1;i<=n;i++) {
scanf("%d",&a[i]);
lx[i]=last[a[i]]+1;
last[a[i]]=i;
}
an=node;
root=maketree(1,n);
int q;
scanf("%d",&q);
for (i=0;i<q;i++) {
scanf("%d%d",&b[i].l,&b[i].r);
b[i].i=i;
}
sort(b,b+q);
x=1;
for (i=0;i<q;i++) {
for (;x<=b[i].r;x++) {
set(root,1,n,lx[x],x,a[x]);
//print();
//getchar();
}
ans[b[i].i]=get(root,1,n,b[i].l,b[i].r);
}
for (i=0;i<q;i++) {
printf("%d\n",ans[i]);
}
return 0;
}