题目链接
题目很长,题意却很简单。
询问任意区间内,最大连续子序列和(其中相等的值不重复计算),可以不选输出0;
1、不存在修改操作
2、子序列中相等的值不重复计算
3、可以选为空的子序列,结果为0
4、数据都在1e5内,其中序列中每个数的绝对值都在1e5内
输入:
1、n个数(总序列长度)
2、下面一行n个数(有正有负)
3、m次询问
4、每次询问[x,y]区间内,最大连续子序列和,其中相等的值不重复计算
直接看样例
样例
9
4 -2 -2 3 -1 -4 2 2 -6
3
1 2
1 5
4 9
输出
4
5
3
有一道比较简单、和这题类似的题目:HDU - 3333Turing Tree
它那题意大致为 : 查询静态区间 i - j 内不同数之和。
里面的离线处理,比起在线的树套树的主席树要简单得多
这种不带修改的题一般可以用离线处理走捷径。把每次加值,看成一次修改。这是刷题可以刷出来的经验。
但这题最难的是如何构造线段树,定义哪些变量,这题我没想出来,看了答案,算作一次经验吧。
题解:
设线段树的叶子为s[i], 每次更新 a[i]的时候,
1、a[i]之前没出现过,s[1] -s[i]区间内加上a[i];那么
s[1] = a[1] + a[2] + a[3] + … + a[i];
s[2] = a[2] + a[3] + … + a[i];
s[3] = a[3] + … + a[i];
…
s[i] = a[i];
2、a[i]在第k位出现过(mp[a[i]]==k),s[k+1] -s[i]区间内加上a[i];那么
s[k+1] = a[k+1] + a[k+2] + a[k+3] + … + a[i];
s[k+2] = a[k+2] + a[k+3] + … + a[i];
…
s[i] = a[i];
转换成区间修改(统一加一个值)的效果,修改范围为[ mp[a[i]]+1 , i ] 。
基础构建完成后,该怎么设计延迟变量来传递其中的关系。
这里引用双延迟标记,一个pre,与mx挂钩,一个lazy,与num挂钩。一般你想不到上面这种模型的构建,也不会想到双延迟标记。
下面是定义+推导
各个变量的含义:
加到第i个值时
num 当前状态下的最大值 如:max(s[1],s[2],.....s[i])(头元素)
当然其左右儿子分别表示max(s[1],..s[i/2])和max(s[i/2+1],..s[i]) 其他情况类似
lazy 正常的延迟标记 将相加的值延迟
---------------------------------------------------
但上述两个变量只有当前情况的最大值,过去可能存在,如
a[x]+...+a[y] (y<i,1<=x<=y)是最大的
上面的情况是之前加到第y个时num的值(y时刻下的s[x])
这种过程在推的过程中是不可回溯的(因为会覆盖)
-->所以要储存过去的情况
---------------------------------------------------
很显然想到设一个mx,表示过去和现在的最大值
-->所以更新时用 t[i].mx=max(t[i].mx,t[i].num);
---------------------------------------------------
而又对于每个mx普通的一个个比较又不好(从1遍历到i)
这里又可以优化,再加一个延迟变量pre
---------------------------------------------------
线段树结构是非线性的(虽然存储是线性的),如果你实在不理解,先回归线性情况
我们对于一个固定序列,求最大子序列和(没有去重情况),
加到第i个,我们通常会求后面的最大相加值,即pre
update更新中,t[i].pre=max(t[i].pre,t[i].lazy);
下推时,pre的变化 t[ls].pre=max(t[ls].pre,t[ls].lazy+t[i].pre);
mx的变化 t[ls].mx=max(t[ls].mx,t[ls].num+t[i].pre);
---------------------------------------------------
综上所述
lazy就正常理解的延迟标记,而pre是从lazy推过来的
num是当前(片面)的最大值,是辅助推mx值的
pre,mx是主要变量
num,lazy是记录变化过程
---------------------------------------------------
实在理解不了,自己逐步推一遍吧
注意点:
1、pre很显然是非负的,可以验证上面思路
2、下推时,对于左右结点,先确定主要值pre,mx,再修改num,lazy这两影响进一步下推的变量
顺序不要搞错。
3、区间相加基操要熟练
关于离线处理
这种思维方式,在线段树中很常见。列举几道题
hdu 3333 Turing Tree
hdu 3874 Necklace
Codeforces Round #136 (Div. 2) D. Little Elephant and Array(附其他人的一个题解)
总结:
大知识点是线段树区间求和,有三个难点:1、线段树的构建。2、离线处理。3、双延迟标记。题目繁琐,但题意简易,却又不好做。
#include
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=5e5+7;
ll read(){
ll x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x*f;
}
int n,m;
ll a[maxn];
#define ls i<<1
#define rs i<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
map<int,int>mp;
struct node{
ll lazy,num,mx,pre;
}t[maxn];
typedef struct choice{
int l,r,id;
ll ans;
}p;
p sz[maxn];
void pushup(int i){
t[i].num=max(t[ls].num,t[rs].num);
t[i].mx=max(t[ls].mx,t[rs].mx);
}
void pushdown(int i){
if(t[i].lazy||t[i].pre){
ll j=t[i].pre,k=t[i].lazy;
t[i].pre=t[i].lazy=0;
t[ls].pre=max(t[ls].pre,t[ls].lazy+j);
t[rs].pre=max(t[rs].pre,t[rs].lazy+j);
t[ls].mx=max(t[ls].mx,t[ls].num+j);
t[rs].mx=max(t[rs].mx,t[rs].num+j);
t[ls].lazy+=k; t[rs].lazy+=k;
t[ls].num+=k; t[rs].num+=k;
}
}
void update(int i,int l,int r,int x,int y,int c){
if(l>y||r<x) return;
if(x<=l&&r<=y){
t[i].num+=c; t[i].lazy+=c;
t[i].pre=max(t[i].pre,t[i].lazy);
t[i].mx=max(t[i].mx,t[i].num);
return;
}
pushdown(i);
int mid=l+r>>1;
update(lson,x,y,c); update(rson,x,y,c);
pushup(i);
}
ll query(int i,int l,int r,int x,int y){
if(l>y||r<x) return 0;
if(x<=l&&r<=y) return t[i].mx;
pushdown(i);
int mid=l+r>>1;
return max(query(lson,x,y),query(rson,x,y));
}
bool cmp1(p x,p y){
return x.r<y.r; }
bool cmp2(p x,p y){
return x.id<y.id; }
int main(){
n=read();
for(int i=1;i<=n;i++) a[i]=read();
m=read();
for(int i=0;i<m;i++){
sz[i].l=read(); sz[i].r=read();
sz[i].id=i;
}
sort(sz,sz+m,cmp1);
int k=0;
for(int i=1;i<=n;i++){
update(1,1,n,mp[a[i]]+1,i,a[i]);
mp[a[i]]=i;
while(k<m&&sz[k].r==i){
sz[k].ans=query(1,1,n,sz[k].l,i);
k++;
}
}
sort(sz,sz+m,cmp2);
for(int i=0;i<m;i++) printf("%lld\n",sz[i].ans);
}
/*
9
4 -2 -2 3 -1 -4 2 2 -6
3
1 2
1 5
4 9
4
5
3
*/