SPOJ1557 GSS2 Can you answer these queries II 历史最值线段树
题意:给出一个长度为$N$的数列,$Q$次询问,每一次询问$[l,r]$之间的最大子段和,相同的数只计算一次。所有数字的绝对值$\leq 10^5$
GSS系列中不板子的大火题,单独拿出来写
因为相同的数字只计算一次,像GSS1中的合并操作就无法进行,传统做法失效,我们需要一种更强大的做法。
考虑到去重,与HH的项链很相似,所以考虑离线、对询问以$r$从小到大进行排序后进行计算。
考虑到每一次$r$的增加都会产生新的可能的最大子段和,我们用如下方式维护线段树:对于第$i$个叶子节点,它包含两个元素:$sum$表示$\sum \limits_i^r num_i$(不算重复元素),$hisMax$表示$\sum \limits_i^r num_i$在曾经的过程中取到的最大值(也就是左端点为$l$,右端点在$[l,r]$之间的最大子段和)。而对于每一个非叶子节点,它的$sum$和$hisMax$都取其左右儿子的最大值。这样每一次询问操作只需要询问$[l,r]$的$hisMax$即可。
对于$r$的右移操作,设$pre_i$表示数字$i$最后一次出现的位置,将右端点从$r$移到$r+1$的过程就是对$pre_{num_{r+1}}$到$r+1$的所有位置加上$num_{r+1}$的操作。
考虑到复杂度,所以我们需要用到懒标记,而pushdown在其中是十分讲究的,具体代码和解释在下面
($h\_tag$表示$hisMax$的标记(相当于在当前$hisMax$还需要加多少),$s\_tag$表示$sum$的懒标记)
inline void pushdown(int now){
if(Tree[now].h_tag){
Tree[lch].hisMax = max(Tree[lch].hisMax , Tree[lch].sum + Tree[now].h_tag);
Tree[rch].hisMax = max(Tree[rch].hisMax , Tree[rch].sum + Tree[now].h_tag);
Tree[lch].h_tag = max(Tree[lch].h_tag , Tree[lch].s_tag + Tree[now].h_tag);
Tree[rch].h_tag = max(Tree[rch].h_tag , Tree[rch].s_tag + Tree[now].h_tag);
/*
h_tag和hisMax实质上都是前缀最大值
在一个后缀加入的时候(也就是Tree[now].h_tag传下来的时候),s_tag和sum可以跟当前的h_tag接上变成一个新的前缀而s_tag与h_tag两个标记对应的区间的左端点一定是一致的,sum和hisMax显然是一致的,于是h_tag和hisMax可以这样转移
*/
Tree[now].h_tag = ;
}
if(Tree[now].s_tag){
Tree[lch].sum += Tree[now].s_tag;
Tree[rch].sum += Tree[now].s_tag;
Tree[lch].s_tag += Tree[now].s_tag;
Tree[rch].s_tag += Tree[now].s_tag;
Tree[now].s_tag = ;
}//这个没什么好说的,基本的线段树操作
}
//注意一定要先传h_tag再传s_tag,因为h_tag和hisMax传下来的时候是与之前的那一段进行连接,而不是与当前计算的这一段进行连接
完整代码:
#include<bits/stdc++.h>
#define lch (now << 1)
#define rch (now << 1 | 1)
#define mid ((l + r) >> 1)
#define int long long
//This code is written by Itst
using namespace std;
inline int read(){
;
;
char c = getchar();
while(c != EOF && !isdigit(c)){
if(c == '-')
f = ;
c = getchar();
}
while(c != EOF && isdigit(c)){
a = (a << ) + (a << ) + (c ^ ');
c = getchar();
}
return f ? -a : a;
}
;
struct node{
int sum , hisMax , s_tag , h_tag;
}Tree[MAXN << ];
struct query{
int l , r , ind;
}now[MAXN];
map < int , int > appear;
int N , Q , num[MAXN] , ans[MAXN];
bool operator <(query a , query b){
return a.r < b.r;
}
inline void pushup(int now){
Tree[now].sum = max(Tree[lch].sum , Tree[rch].sum);
Tree[now].hisMax = max(Tree[lch].hisMax , Tree[rch].hisMax);
}
inline void pushdown(int now){
if(Tree[now].h_tag){
Tree[lch].hisMax = max(Tree[lch].hisMax , Tree[lch].sum + Tree[now].h_tag);
Tree[rch].hisMax = max(Tree[rch].hisMax , Tree[rch].sum + Tree[now].h_tag);
Tree[lch].h_tag = max(Tree[lch].h_tag , Tree[lch].s_tag + Tree[now].h_tag);
Tree[rch].h_tag = max(Tree[rch].h_tag , Tree[rch].s_tag + Tree[now].h_tag);
Tree[now].h_tag = ;
}
if(Tree[now].s_tag){
Tree[lch].sum += Tree[now].s_tag;
Tree[rch].sum += Tree[now].s_tag;
Tree[lch].s_tag += Tree[now].s_tag;
Tree[rch].s_tag += Tree[now].s_tag;
Tree[now].s_tag = ;
}
}
void modify(int now , int l , int r , int L , int R , int add){
if(l >= L && r <= R){
Tree[now].s_tag += add;
Tree[now].sum += add;
Tree[now].hisMax = max(Tree[now].hisMax , Tree[now].sum);
Tree[now].h_tag = max(Tree[now].h_tag , Tree[now].s_tag);
return;
}
pushdown(now);
if(mid >= L)
modify(lch , l , mid , L , R , add);
if(mid < R)
modify(rch , mid + , r , L , R , add);
pushup(now);
}
int query(int now , int l , int r , int L , int R){
if(l >= L && r <= R)
return Tree[now].hisMax;
pushdown(now);
;
if(mid >= L)
maxN = query(lch , l , mid , L , R);
if(mid < R)
maxN = max(maxN , query(rch , mid + , r , L , R));
return maxN;
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1557.in" , "r" , stdin);
//freopen("1557.out" , "w" , stdout);
#endif
N = read();
; i <= N ; ++i)
num[i] = read();
Q = read();
; i <= Q ; ++i){
now[i].l = read();
now[i].r = read();
now[i].ind = i;
}
sort(now + , now + Q + );
; i <= Q ; ++i){
].r + ; j <= now[i].r ; ++j){
modify( , , N , appear[num[j]] + , j , num[j]);
appear[num[j]] = j;
}
ans[now[i].ind] = query( , , N , now[i].l , now[i].r);
}
; i <= Q ; ++i)
printf("%lld\n" , ans[i]);
;
}
SPOJ1557 GSS2 Can you answer these queries II 历史最值线段树的更多相关文章
- SPOJ GSS2 - Can you answer these queries II(线段树 区间修改+区间查询)(后缀和)
GSS2 - Can you answer these queries II #tree Being a completist and a simplist, kid Yang Zhe cannot ...
- bzoj 2482: [Spoj GSS2] Can you answer these queries II 线段树
2482: [Spoj1557] Can you answer these queries II Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 145 ...
- spoj gss2 : Can you answer these queries II 离线&&线段树
1557. Can you answer these queries II Problem code: GSS2 Being a completist and a simplist, kid Yang ...
- SPOJ GSS2 Can you answer these queries II
Time Limit: 1000MS Memory Limit: 1572864KB 64bit IO Format: %lld & %llu Description Being a ...
- SP1557 GSS2 - Can you answer these queries II
一开始看不懂题解,看懂了题解之后觉得还是挺妙的. 好多题解里都提到了HH的项链,但是我觉得关系并不大啊…… 先把所有询问离线下来按照右端点排序,按照询问的要求一个一个加入数字,怎么加入数字,我们设计一 ...
- SPOJ GSS2 Can you answer these queries II ——线段树
[题目分析] 线段树,好强! 首先从左往右依次扫描,线段树维护一下f[].f[i]表示从i到当前位置的和的值. 然后询问按照右端点排序,扫到一个位置,就相当于查询区间历史最值. 关于历史最值问题: 标 ...
- SP1557 GSS2 - Can you answer these queries II(线段树)
传送门 线段树好题 因为题目中相同的只算一次,我们可以联想到HH的项链,于是考虑离线的做法 先把所有的询问按$r$排序,然后每一次不断将$a[r]$加入线段树 线段树上维护四个值,$sum,hix,s ...
- SPOJ 1557 GSS2 - Can you answer these queries II (线段树+维护历史最值)
都说这题是 GSS 系列中最难的,今天做了一下,名副其实 首先你可以想到各种各样的在线乱搞想法,线段树,主席树,平衡树,等等,但发现都不太可行. 注意到题目也没有说强制在线,因此可以想到离线地去解决这 ...
- Can you answer these queries I SPOJ - GSS1 (线段树维护区间连续最大值/最大连续子段和)
You are given a sequence A[1], A[2], ..., A[N] . ( |A[i]| ≤ 15007 , 1 ≤ N ≤ 50000 ). A query is defi ...
随机推荐
- 使用Topshelf创建自宿主的Windows服务程序
在传统的Windows服务开发过程中,需要添加一个服务安装程序,里面写安装,启动和停止服务等逻辑.现在,使用TopSelf可以简化这个过程.具体请看官网说明: http://docs.topshelf ...
- eclipse显示代码行数
最近做的手机APP正在进行最后一部分了,在一个类中估计要写上千行代码,来回的拉动滚动条太麻烦了,于是发现为什么我得eclipse不显示代码行数呢 其他C什么的编译器都显示的. 于是百度了一下,一下子 ...
- [20180122]列统计与直方图.txt
[20180122]列统计与直方图.txt --//昨天看了https://jonathanlewis.wordpress.com/2018/01/18/column-stats/,提到分析metho ...
- Asp.net Mvc身份验证
1.安装组件 Microsoft.AspNet.Identity.Core,身份认证核心组件 安装Microsoft.AspNet.Identity.EntityFramework,EF实现身份认证 ...
- linux调度器源码分析 - 概述(一)
本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 引言 调度器作为操作系统的核心部件,具有非常重要的意义,其随着linux内核的更新也不断进行着更新.本系列文章通 ...
- Django学习---py3下的富文本编辑器的使用
背景说明: Ueditor HTML编辑器是百度开源的HTML编辑器,但是在Python3下调用报错,找不到widgets模块,经查发现,DjangoUeditor是基于Python 2.7的,对Py ...
- sql server 2008R2无人值守批处理脚本自动化安装
▲版权声明:本文为博主原创文章,未经博主允许不得转载. Microsoft SQL Server 2008 R2是一款软件,提供完整的企业级技术与工具,帮助您以最低的总拥有成本获得最有价值的信息.您可 ...
- Flask消息闪现
目录 Flask消息闪现 简单的例子 闪现消息的类别 过滤闪现消息 Message Flashing 参考 Flask消息闪现 一个好的应用和用户界面都需要良好的反馈.如果用户得不到足够的反馈,那么应 ...
- 【PAT】B1075 链表元素分类(25 分)
这道题算有点难,心目中理想的难度. 不能前怕狼后怕虎,一会担心超时,一会又担心内存过大,直接撸 将三部分分别保存到vector 有意思的在于输出 分别输出第一个的add和num 中间输出nextadd ...
- February 9th, 2018 Week 6th Friday
Every one of us want to ameliorate our own condition. You can only cure retail but you can prevent w ...