都说这题是 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 (线段树+维护历史最值)的更多相关文章

  1. 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 ...

  2. spoj 1557 GSS3 - Can you answer these queries III 线段树

    题目链接 给出n个数, 2种操作, 一种是将第x个数改为y, 第二种是询问区间[x,y]内的最大连续子区间. 开4个数组, 一个是区间和, 一个是区间最大值, 一个是后缀的最大值, 一个是前缀的最大值 ...

  3. SPOJ GSS2 Can you answer these queries II ——线段树

    [题目分析] 线段树,好强! 首先从左往右依次扫描,线段树维护一下f[].f[i]表示从i到当前位置的和的值. 然后询问按照右端点排序,扫到一个位置,就相当于查询区间历史最值. 关于历史最值问题: 标 ...

  4. 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 ...

  5. 【BZOJ2482】[Spoj1557] Can you answer these queries II 线段树

    [BZOJ2482][Spoj1557] Can you answer these queries II Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和( ...

  6. 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]| ≤ ...

  7. 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 ...

  8. Spoj 1557 Can you answer these queries II 线段树 随意区间最大子段和 不反复数字

    题目链接:点击打开链接 每一个点都是最大值,把一整个序列和都压缩在一个点里. 1.普通的区间求和就是维护2个值,区间和Sum和延迟标志Lazy 2.Old 是该区间里出现过最大的Sum, Oldlaz ...

  9. 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 ...

随机推荐

  1. 2020年09月15日-项目开发-python二次处理代码文件

    Caterpillar通过将BPMN生成为solidity代码后, 我需要对solidity代码做二次处理,即在其中的特定函数中插入event类型,以便去做事件监听. 最终生成的不仅包括solidit ...

  2. 异构智联Wi-Fi+蓝牙模组,连接快、准、稳!

    下班回家打开门,电灯.电视.空调.音响.电动窗帘.扫地机器人--一呼百应,有序开工,原本冰冷的房子立刻变成了温暖港湾.可以说,舒适便捷的智能设备已经完全融入了我们的生活中. 从单一场景.单一设备,到现 ...

  3. javascript-原生-闭包

    1.变量的作用域 前提:这里只全部都通过var创建的变量或对象 1.全局变量:函数外创建变量 var x=10; function test(){ alert("全局变量在test函数中&q ...

  4. Golang通脉之接口

    接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节. 接口类型 在Go语言中接口(interface)是一种类型,一种抽象的类型. interface是 ...

  5. springboot 事务执行全流程分析

    springboot 事务执行全流程分析 目录 springboot 事务执行全流程分析 1. 事务方法执行前的准备工作 2. 业务代码的调用 3. 事务方法执行后处理 4. 业务代码在事务和非事务中 ...

  6. 解决git clone慢问题

    解决git clone慢 关于Git克隆或是上传代码龟速的问题真是让人很恼火,这里对于网上的两种解决方案进行摘录. 利用码云克隆github项目 亲测有效 进入码云,新建一个仓库: 在创建的最后选择导 ...

  7. word-ladder leetcoder C++

    Given two words (start and end), and a dictionary, find the length of shortest transformation sequen ...

  8. Windows7下面手把手教你安装Django - Hongten

    我所使用的操作系统是Windows7,内存是2G 在搜索了一些资料发现,对于Django的安装,详细的真的很少,都说的很简化,然而,这篇blog可以手把手教你成功安装Django 对于Django的详 ...

  9. exec系统调用 && 进程的加载过程

    exec系统调用会从指定的文件中读取并加载指令,并替代当前调用进程的指令.从某种程度上来说,这样相当于丢弃了调用进程的内存,并开始执行新加载的指令. exec系统调用会保留当前的文件描述符表单.所以任 ...

  10. Linux部署Apollo+.Net Core简单使用

    Apollo官方网站非常详细,以下只是本人学习过程的整理 一.概念 Apollo(阿波罗)是一款可靠的分布式配置管理中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并 ...