题意
给出长度为(n)的序列(a_i),(q) 次询问,求最大子段和,相同的数只算一次
(1 ≤ n,q≤ 100000)
(-100000≤a_i≤100000)
分析
没有修改操作,考虑离线处理
正序扫描序列加入每个元素,并在线段树中的每个叶子节点(i)维护区间([i,j])去掉重复元素后的区间和((j)为目前扫描到的位置)
如何去重
定义(pre[i])表示(i)上一次出现的位置
如果一个元素(a_i)在(pre[a_i])的位置出现过了,那就只在区间([pre[a_i]+1,i])中加入它(区间加),相当于自动完成了去重
如何处理询问
把每个询问离线下来,按右端点排序,对于每个询问([l,r]),在加入(a_r)后查询(max(a_i+a_{i+1}...+a_{j-1}+a_j)) (l≤i≤j≤r)(区间查询),既区间([l,r])中的历史最大值
如何维护历史最大值
线段树中的下放操作有较大的"时间差",直接和当前值取max肯定不行
于是我们在线段树中维护四个值:最大去重和, 历史最大去重和, 历史最大标记, 目前标记
下放一个节点时,用该节点的历史最大标记去更新子节点的历史最大去重和和历史最大标记即可
(code)
#include<bits/stdc++.h>
using namespace std;
#define lson node<<1
#define rson node<<1|1
const int MAXN = 100010;
#define int long long
inline int read(){
int X=0; bool flag=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
if(flag) return X;
return ~(X-1);
}
int n,m,a[MAXN],pre[20*MAXN],ans[MAXN];
struct query{
int l,r,id;
}q[MAXN];
bool cmp(query a,query b){
return a.r<b.r;
}
struct st{
int max,hismax;
int tag,histag;
}tree[MAXN<<2];
void pushup(int node){
tree[node].max = max(tree[lson].max,tree[rson].max);
tree[node].hismax = max(tree[lson].hismax,tree[rson].hismax);
}
void pushdown(int node,int fa){
tree[node].hismax = max(tree[node].hismax,tree[fa].histag+tree[node].max);//更新历史最大值和历史最大tag
tree[node].histag = max(tree[node].histag,tree[fa].histag+tree[node].tag);
tree[node].max+=tree[fa].tag;
tree[node].tag+=tree[fa].tag;
}
void PUSHDOWN(int node){
if(!tree[node].tag) return;
pushdown(lson,node);
pushdown(rson,node);
tree[node].histag = tree[node].tag = 0;
}
void modify(int node,int l,int r,int x,int y,int val){
if(x<=l&&y>=r){
tree[node].max+=val,tree[node].tag+=val;
tree[node].hismax = max(tree[node].hismax,tree[node].max);
tree[node].histag = max(tree[node].histag,tree[node].tag);
return;
}
PUSHDOWN(node);
int mid = (l+r)>>1;
if(x<=mid) modify(lson,l,mid,x,y,val);
if(y>mid) modify(rson,mid+1,r,x,y,val);
pushup(node);
}
int query(int node,int l,int r,int x,int y){
if(x<=l&&y>=r){
return tree[node].hismax;
}
PUSHDOWN(node);
int mid = (l+r)>>1;
if(y<=mid) return query(lson,l,mid,x,y);
if(x>mid) return query(rson,mid+1,r,x,y);
return max(query(lson,l,mid,x,y),query(rson,mid+1,r,x,y));
}
signed main(){
n = read();
for(int i=1;i<=n;i++) a[i] = read();
m = read();
for(int i=1;i<=m;i++){
q[i].l = read(),q[i].r = read();
q[i].id = i;
}
sort(q+1,q+1+m,cmp);
int j = 1;
for(int i=1;i<=n;i++){
modify(1,1,n,pre[a[i]+100000]+1,i,a[i]);
pre[a[i]+100000] = i;
while(i==q[j].r&&j<=m) ans[q[j].id] = query(1,1,n,q[j].l,q[j].r),j++;
}
for(int i=1;i<=m;i++){
printf("%lld
",ans[i]);
}
}