SPOJ 1557 GSS2 - Can you answer these queries II (线段树+维护历史最值)
都说这题是 GSS 系列中最难的,今天做了一下,名副其实
首先你可以想到各种各样的在线乱搞想法,线段树,主席树,平衡树,等等,但发现都不太可行。
注意到题目也没有说强制在线,因此可以想到离线地去解决这道题。
我们把询问按照右端点从小到大排序。假设当前询问的右端点为 \(i\)。
定义 \(s_j\) 为 \([j,i]\) 中不重复数字的和。我们建一棵线段树维护 \(s_j\) 的最大值。
这样修改起来就比较自然了,当右端点从 \(i-1\) 变到 \(i\) 的时候,记 \(a_i\) 上一次出现的位置为 \(k\),那么这个 \(a_i\) 只会对 \(s_{k+1},s_{k+2},\dots,s_i\) 产生贡献,也就是说我们在线段树上 \([k+1,i]\) 位置上的数 \(+a_i\)。
询问也比较容易。询问 \((l,i)\) 的答案就是 \(s_l,s_{l+1},\dots,s_i\) 的历史最大值。
这样原题就转化为一道看起来比较可做的 DS 了,要你维护一个序列,支持:
- 区间加
- 区间历史最大值
之前写过一道类似的题题号什么我忘了,可现在忘了怎么做了/kk,只好看题解再推一遍。
线段树区间维护四个东西 \(mx,hmx,lz,hlz\) 表示最大值,历史最大值,区间加标记,历史最大区间加标记(历史出现过的懒标记的最大值)。
上推操作就不用说了吧,直接对 \(mx,hmx\) 取 \(\max\)。。。。。。
区间加上一个值 \(v\),那么最大值肯定也会加上 \(v\),历史最大值就和当前最大值取 \(\max\),懒标记也同理。
最复杂的就是如何下传标记。
例如我们现在有一段操作序列 \(+1-3+4-2-1+5-2\),那么此时懒标记为 \(+2\),历史最大懒标记为 \(+4\)(\(+1-3+4-2-1+4\))。
然后它的儿子当前最大值为 \(2\),历史最大值为 \(3\),当前懒标记为 \(-1\),历史最大懒标记为 \(+1\)。
那么:
- \(mx\) 显然直接加上父亲的懒标记即可,\(2+1-3+4-2-1+5-2=2+2=4\)。
- \(hmx\) 拿当前最大值 \(2\) 加上历史最大懒标记 \(+4\)(\(2+1-3-4-2-1+5=6\)),与原来历史最大值 \(3\) 比较。
- \(lz\) 也是直接加上父亲的 \(lz\) 即可,\(-1+2=+1\)
- \(hlz\) 也拿当前最大懒标记加上历史最大懒标记 \(+4\)(\(-1+1-3-4-2-1+5=+3\)),与原来历史最大懒标记 \(+1\) 比较。
最后,重中之重,下放懒标记的顺序一定要注意。
/*
Contest: -
Problem: SP1557
Author: tzc_wk
Time: 2020.8.8
*/
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a) a.begin(),a.end()
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,0x3f,sizeof(a))
#define fillsmall(a) memset(a,0xcf,sizeof(a))
#define y1 y1010101010101
#define y0 y0101010101010
#define int long long
typedef pair<int,int> pii;
inline int read(){
int x=0,neg=1;char c=getchar();
while(!isdigit(c)){
if(c=='-') neg=-1;
c=getchar();
}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
return x*neg;
}
int n=read(),m,a[100005],ans[100005];
struct _query{
int l,r,id;
friend bool operator <(_query a,_query b){
return a.r<b.r;
}
} q[100005];
struct node{
int l,r,mx,hmx,lz,hlz;
} s[100005<<2];
inline void pushup(int k){
s[k].mx=max(s[k<<1].mx,s[k<<1|1].mx);
s[k].hmx=max(s[k<<1].hmx,s[k<<1|1].hmx);
}
inline void build(int k,int l,int r){
s[k].l=l;s[k].r=r;
if(l==r) return;
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
inline void pushdown(int k){
s[k<<1].hmx=max(s[k<<1].hmx,s[k<<1].mx+s[k].hlz);
s[k<<1|1].hmx=max(s[k<<1|1].hmx,s[k<<1|1].mx+s[k].hlz);
s[k<<1].mx+=s[k].lz;
s[k<<1|1].mx+=s[k].lz;
s[k<<1].hlz=max(s[k<<1].hlz,s[k<<1].lz+s[k].hlz);
s[k<<1|1].hlz=max(s[k<<1|1].hlz,s[k<<1|1].lz+s[k].hlz);
s[k<<1].lz=s[k<<1].lz+s[k].lz;
s[k<<1|1].lz=s[k<<1|1].lz+s[k].lz;
s[k].lz=s[k].hlz=0;
}
inline void add(int k,int l,int r,int x){
if(l<=s[k].l&&s[k].r<=r){
s[k].mx+=x;s[k].hmx=max(s[k].hmx,s[k].mx);
s[k].lz+=x;s[k].hlz=max(s[k].hlz,s[k].lz);
return;
}
pushdown(k);
int mid=(s[k].l+s[k].r)>>1;
if(r<=mid) add(k<<1,l,r,x);
else if(l>mid) add(k<<1|1,l,r,x);
else add(k<<1,l,mid,x),add(k<<1|1,mid+1,r,x);
pushup(k);
}
inline int query(int k,int l,int r){
if(l<=s[k].l&&s[k].r<=r){
return s[k].hmx;
}
pushdown(k);
int mid=(s[k].l+s[k].r)>>1;
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else return max(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
}
map<int,int> mp;
signed main(){
fz(i,1,n) a[i]=read();
m=read();fz(i,1,m) q[i].l=read(),q[i].r=read(),q[i].id=i;
sort(q+1,q+m+1);
build(1,1,n);
int cur=1;
fz(i,1,n){
add(1,mp[a[i]]+1,i,a[i]);mp[a[i]]=i;
while(cur<=m&&q[cur].r<=i){
ans[q[cur].id]=query(1,q[cur].l,q[cur].r);cur++;
}
}
fz(i,1,m) printf("%lld\n",ans[i]);
return 0;
}
SPOJ 1557 GSS2 - Can you answer these queries II (线段树+维护历史最值)的更多相关文章
- 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 1557 GSS3 - Can you answer these queries III 线段树
题目链接 给出n个数, 2种操作, 一种是将第x个数改为y, 第二种是询问区间[x,y]内的最大连续子区间. 开4个数组, 一个是区间和, 一个是区间最大值, 一个是后缀的最大值, 一个是前缀的最大值 ...
- SPOJ GSS2 Can you answer these queries II ——线段树
[题目分析] 线段树,好强! 首先从左往右依次扫描,线段树维护一下f[].f[i]表示从i到当前位置的和的值. 然后询问按照右端点排序,扫到一个位置,就相当于查询区间历史最值. 关于历史最值问题: 标 ...
- SPOJ 1557. Can you answer these queries II 线段树
Can you answer these queries II Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 https://www.spoj.com/pr ...
- 【BZOJ2482】[Spoj1557] Can you answer these queries II 线段树
[BZOJ2482][Spoj1557] Can you answer these queries II Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和( ...
- SPOJ GSS1 - Can you answer these queries I(线段树维护GSS)
Can you answer these queries I SPOJ - GSS1 You are given a sequence A[1], A[2], -, A[N] . ( |A[i]| ≤ ...
- SPOJ - GSS1-Can you answer these queries I 线段树维护区间连续和最大值
SPOJ - GSS1:https://vjudge.net/problem/SPOJ-GSS1 参考:http://www.cnblogs.com/shanyr/p/5710152.html?utm ...
- Spoj 1557 Can you answer these queries II 线段树 随意区间最大子段和 不反复数字
题目链接:点击打开链接 每一个点都是最大值,把一整个序列和都压缩在一个点里. 1.普通的区间求和就是维护2个值,区间和Sum和延迟标志Lazy 2.Old 是该区间里出现过最大的Sum, Oldlaz ...
- 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 ...
随机推荐
- keras框架下的深度学习(一)手写体识别
这个系列文章主要记录使用keras框架来搭建深度学习模型的学习过程,其中有一些自己的想法和体会,主要学习的书籍是:Deep Learning with Python,使用的IDE是pycharm. 在 ...
- ES2020新特性记录
1.可选链操作符 // oldlet ret = obj && obj.first && obj.first.second// newlet ret = obj?.fi ...
- (六)、Docker 之 Dockerfile
1.什么是Dockerfile Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本. 2.Dockerfile解析过程 前提认知: 每条保留字指令都必须为大写字母 ...
- 生产环境部署springcloud微服务启动慢的问题排查
今天带来一个真实案例,虽然不是什么故障,但是希望对大家有所帮助. 一.问题现象: 生产环境部署springcloud应用,服务部署之后,有时候需要10几分钟才能启动成功,在开发测试环境则没有这个问题. ...
- Go语言核心36讲(Go语言进阶技术十)--学习笔记
16 | go语句及其执行规则(上) 我们已经知道,通道(也就是 channel)类型的值,可以被用来以通讯的方式共享数据.更具体地说,它一般被用来在不同的 goroutine 之间传递数据.那么 g ...
- OKhttp3的使用教程
首先在build.gradle下的dependencies下添加引用. implementation "com.squareup.okhttp3:okhttp:4.9.0" 然后编 ...
- P2120 [ZJOI2007]仓库建设
P2120 [ZJOI2007]仓库建设 怎么说呢?算是很水的题了吧... 只要不要一开始就把dp想错就行... #include<bits/stdc++.h> #define ll lo ...
- hdu 5055 Bob and math problem (很简单贪心)
给N个数字(0-9),让你组成一个数. 要求:1.这个数是奇数 2.这个数没有前导0 问这个数最大是多少. 思路&解法: N个数字从大到小排序,将最小的奇数与最后一位交换,把剩下前N-1位从大 ...
- docker使用redis过程出现的问题记录
第一次使用docker搭建成功了单机版redis,但在使用过程中,还是遇到了不少问题,故而先把这些问题记录下来,以防后面再出现会忘记. 目前,只是在docker中搭建了三个单机版的容器,打算先捣鼓一周 ...
- 基于Lucene的全文检索实践
由于项目的需要,使用到了全文检索技术,这里将前段时间所做的工作进行一个实践总结,方便以后查阅.在实际的工作中,需要灵活的使用lucene里面的查询技术,以达到满足业务要求与搜索性能提升的目的. 一.全 ...