1. 程式人生 > 實用技巧 >SP1557 GSS2 - Can you answer these queries II

SP1557 GSS2 - Can you answer these queries II

題目連結

題意

給出長度為\(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]\)中的歷史最大值

如何維護歷史最大值

線上段樹中維護四個值:最大去重和, 歷史最大去重和, 歷史最大標記, 目前標記

下放一個節點時,用該節點的歷史最大標記去更新子節點的歷史最大去重和和歷史最大標記即可

\(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\n",ans[i]);
	} 
}