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 ...
随机推荐
- python os.walk处理树状目录结构的文件
在项目工作中,时常需要用到处理文件的方法,尤其是在windows环境下的树状目录结构 os.walk恰好能完美的处理这种树状目录结构文件,能高效地帮助我们得到我们需要处理的文件 目录结构: Deskt ...
- 【数据结构与算法Python版学习笔记】树——树的遍历 Tree Traversals
遍历方式 前序遍历 在前序遍历中,先访问根节点,然后递归地前序遍历左子树,最后递归地前序遍历右子树. 中序遍历 在中序遍历中,先递归地中序遍历左子树,然后访问根节点,最后递归地中序遍历右子树. 后序遍 ...
- SpringCloud 2020.0.4 系列之 Feign
1. 概述 老话说的好:任何问题都有不止一种的解决方法,当前的问题没有解决,只是还没有发现解决方法,而并不是无解. 言归正传,之前我们聊了 SpringCloud 的服务治理组件 Eureka,今天我 ...
- PinPoint单节点部署及客户端配置方法
在一次做项目中,需要涉及全链路压测,为了更好定位链路中某一节点可能会出现的问题,在繁忙之余,快速部署及应用了该链路工具,分享给大家~ 话不多说,开始部署~ 一.环境配置1.1 获取需要的依赖包进入ho ...
- OO第二单元电梯作业总结
目录 目录一.第一次作业分析设计策略基于度量分析程序结构二.第二次作业分析设计策略基于度量分析程序结构三.第三次作业分析设计策略基于度量分析程序结构四.分析自己程序的bug五.发现别人程序bug所采用 ...
- 攻防世界 web5.disabled_button
我觉得戴上手套按应该可以! 方法一: 打开网址,发现flag按钮无法点击,F12查看源代码,删除disabled=" ",flag就点击了. 方法二 POST请求, 先分析一下源代 ...
- systemverilog 字符串类型
转载:https://blog.csdn.net/Holden_Liu/article/details/100727957 传统的Veriog仅仅支持文字表述上的字符串, 而SystemVerilog ...
- Linux上的多进程间通信机制
最近项目需要一个类似于Android上广播通信机制,方便多进程间相互通信,可以是一对多,多对一,或者多对多. 大致如下 Linux现有的进程间通信能用的只有 管道 消息队列 信号量(这个还只能算同步机 ...
- 重新整理 .net core 实践篇——— filter[四十四]
前言 简单介绍一下filter 正文 filter 的种类,微软文档中写道: 每种筛选器类型都在筛选器管道中的不同阶段执行: 授权筛选器最先运行,用于确定是否已针对请求为用户授权. 如果请求未获授权, ...
- leetcode 剪绳子系列
### 剪绳子一 利用动态规划 状态转移方程 为啥是这个样子?首先 代表 长度为i的绳子被剪去j,且继续剪(子问题) 表示长度为i的绳子被剪去j,不剪了的乘积 注意初始化: n<2 f=0 ...