不知道第几次回顾了,每次回顾感觉都有新的收获

这题YYZ认为非常的简单,我们一起去%%%她吧(洛谷$id: 54050$)

题面

给出$n$个数,有$q$个询问,求最大子段和,注意相同的数只算一次

做法

考虑神奇的转化

定义区间$[l,r]$的最大子段和为$A(l, r)$

定义左端点在$l$,右端点在$[l,r]$之间的区间和(重复元素记一次)的最大值为$P(l, r)$

定义左端点在$l$,右端点为$r$的区间和(重复元素记一次)为$S(l,r)$

那么,我们有转化$A(l, r) = max(P(l, r), P(l + 1, r), ..., P(r, r))$

这是显然成立的,相当于根据子段和的左端点进行分类后求最大值

一个疯狂的想法

我们枚靠$r$

每次$r$往右扩展时,

如果我们能动态地维护$P(l,r)...P(r,r)$

那么,对于每个$r$而言,

只要我们能用一种能快速求出$max(P(l,r), P(l +1, r),...,P(r,r))$的数据结构

我们就能回答询问右端点是$r$的所有询问

理下思路:

1.给所有查询按右端点排序

2.枚举右端点

3.在枚举的途中动态地维护$P(l,r)...P(r,r)$

($P(l,r)...P(r,r)$对应区间$[l,r]$)

4.用线段树快速回答右端点是$r$的询问

由定义:$P(l,r) = max(S(l,l), S(l,l+1),S(l,l+2),.....,S(l,r))$

考虑当$r$从$i-1$移动到$i$时,有$P(l,i) = max(P(l, i - 1), S(l, i))$(由定义)

我们从这个式子考虑维护

记$val[i]$表示$i$位置的元素值

记$pre[i]$表示满足$val[i] = val[j]$和$j < i$的最大的$j$

对于$[1, pre[i]]$的$j$而言,由于重复元素不计数,有$S(j,i) = S(j, i - 1)$

即$P(j, i) = P(j, i - 1)$,因此,线段树维护时跳过这一段即可保证不重

对于$[pre[j] + 1, i]$的$j$而言,有$S(j, i) = S(j, i - 1) + val[j]$

我们只要维护$S(j, i)$和$P(j, i)$就可以了

但是,由于是区间修改,因此我们要考虑合理地设计标记来维护

(假设$r$枚举到$i$)

不妨设$tag[j]$为为了维护$S(j, i)$而生的懒惰标记

设$lazy[j]$为为了维护$P(j, i)$而生的懒惰标记

注意之间的相对顺序即可,具体看代码注释

#include <cstdio>
#include <iostream>
#include <algorithm>
#define rem template <typename re>
#define ls (p << 1)
#define rs (p << 1 | 1)
#define ll long long
#define sid 800005
using namespace std; char RR[];
extern inline char gc() {
static char *S = RR + , *T = RR + ;
if(S == T) S = RR, fread(RR, , , stdin);
return *S ++;
}
inline int read() {
int p = , w = ; char c = gc();
while(c > '' || c < '') { if(c == '-') w = -; c = gc(); }
while(c >= '' && c <= '') { p = p * + c - ''; c = gc(); }
return p * w;
} int n, m, ret;
int val[sid], pre[sid];
ll ans[sid]; struct Seg {
ll P, S, tag, lazy;
//t[p].P -> max(P(l,i)...P(r,i))
//t[p].S -> max(S(l,i)...S(r,i))
//t[p].tag -> 给[l, r]的S未加的值
//t[p].lazy -> 所有tag中最大的那个值
} tr[sid]; struct Question {
int l, r, id;
friend bool operator < (Question a, Question b) {
return a.r < b.r;
}
} q[sid]; void Pushdown(int p) {
if(!tr[p].tag && !tr[p].lazy) return;
tr[ls].P = max(tr[ls].P, tr[ls].S + tr[p].lazy);
//取S最大值和lazy最大值相加绝对是最大值
tr[ls].lazy = max(tr[ls].lazy, tr[ls].tag + tr[p].lazy);
//更新lazy
tr[ls].S += tr[p].tag; tr[ls].tag += tr[p].tag;
//依照定义
tr[rs].P = max(tr[rs].P, tr[rs].S + tr[p].lazy);
tr[rs].lazy = max(tr[rs].lazy, tr[rs].tag + tr[p].lazy);
tr[rs].S += tr[p].tag; tr[rs].tag += tr[p].tag;
tr[p].tag = ; tr[p].lazy = ;
} void Update(int p) {
tr[p].S = max(tr[ls].S, tr[rs].S);
tr[p].P = max(tr[ls].P, tr[rs].P);
} void Modify(int p, int l, int r, int ml, int mr, int mc) {
if(ml <= l && mr >= r) {
tr[p].tag += mc; tr[p].S += mc;
//对[l,r]中所有数+mc,则t[p].S += mc
//自然t[p].tag += mc
tr[p].lazy = max(tr[p].lazy, tr[p].tag);
//定义
tr[p].P = max(tr[p].S, tr[p].P);
//定义
return;
}
Pushdown(p);
int mid = (l + r) >> ;
if(ml <= mid) Modify(p << , l, mid, ml, mr, mc);
if(mr > mid) Modify(p << | , mid + , r, ml, mr, mc);
Update(p);
} ll Query(int p, int l, int r, int ml, int mr) {
if(ml <= l && mr >= r) return tr[p].P;
Pushdown(p); ll ans = -;
int mid = (l + r) >> ;
if(ml <= mid) ans = Query(p << , l, mid, ml, mr);
if(mr > mid) ans = max(ans, Query(p << | , mid + , r, ml, mr));
return ans;
} int main() {
n = read();
for(int i = ; i <= n; i ++) val[i] = read();
m = read();
for(int i = ; i <= m; i ++)
q[i].l = read(), q[i].r = read(), q[i].id = i;
sort(q + , q + m + ); int tail = ;
for(int i = ; i <= n; i ++) {
if(tail > m) break;
int nv = val[i] + ; //注意负数
Modify(, , n, pre[nv] + , i, val[i]);
pre[nv] = i;
while(q[tail].r == i) ans[q[tail].id] = Query(, , n, q[tail].l, i), tail ++;
}
for(int i = ; i <= m; i ++) printf("%lld\n", ans[i]);
return ;
}

SPOJ1557 GSS2的更多相关文章

  1. SPOJ1557 GSS2 Can you answer these queries II 历史最值线段树

    传送门 题意:给出一个长度为$N$的数列,$Q$次询问,每一次询问$[l,r]$之间的最大子段和,相同的数只计算一次.所有数字的绝对值$\leq 10^5$ GSS系列中不板子的大火题,单独拿出来写 ...

  2. BZOJ2482: [Spoj1557] Can you answer these queries II

    题解: 从没见过这么XXX的线段树啊... T_T 我们考虑离线做,按1-n一个一个插入,并且维护区间[ j,i](i为当前插入的数)j<i的最优值. 但这个最优值!!! 我们要保存历史的最优值 ...

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

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

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

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

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

  7. SPOJ GSS2 Can you answer these queries II

    Time Limit: 1000MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu Description Being a ...

  8. BZOJ2883 : gss2加强版

    首先离散化颜色 设pre[x]表示与x颜色相同的点上一次出现的位置,对于每种颜色开一个set维护 修改时需要修改x.x修改前的后继.x修改后的后继 询问[l,r]等价于询问[l,r]内pre[x]&l ...

  9. 【SPOJ - GSS2】Can you answer these queries II(线段树)

    区间连续不重复子段最大值,要维护历史的最大值和当前的最大值,打两个lazy,离线 #include<cstdio> #include<cstring> #include< ...

随机推荐

  1. 【BZOJ】2599: [IOI2011]Race 点分治

    [题意]给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000.注意点从0开始编号,无解输出-1. [算法]点分治 [题解] ...

  2. Windows Live Writer博客草稿迁移的一种解决方案

    作为一个苦逼的码农,喜欢写博客做总结是很正常的事,写博客写的久的人都接触过各种客户端工具,最流行的就是Windows Live Writer了. 作为一个苦逼的码农,换电脑也是很经常的事,经常会出现一 ...

  3. IE9 下 ellipsis bug fix

    fiddle: http://jsfiddle.net/tagliala/TtbuG/10/ original: https://github.com/FortAwesome/Font-Awesome ...

  4. perl6 登录phpmyadmin

    use HTTP::UserAgent; my $ua = HTTP::UserAgent.new; my $url = 'http://localhost/phpMyAdmin/index.php' ...

  5. 9 - Python函数定义-位置参数-返回值

    目录 1 函数介绍 1.1 为什么要使用函数 1.2 Python中的函数 2 函数的基本使用 3 函数的参数 3.1 参数的默认值 3.2 可变参数 3.2.1 可变位置传参 3.2.2 可变关键字 ...

  6. angular中使用AMEXIO

    1.用NPM添加依赖到项目中,amexio需要先添加以下四个依赖到项目 npm install jquery@3.2.1  --save npm install bootstrap@4.0.0-alp ...

  7. 利用Google API生成二维码

    什么是二维码:二维码是二维条形码的一种,可以将网址.文字.照片等信息通过相应的编码算法编译成为一个方块形条码图案,手机用户可以通过摄像头和解码软件将相关信息重新解码并查看内容.读取方式:利用30万画素 ...

  8. Vue进阶篇

    前引 今天是2018年12月30,虽不是2018年的最后一天,但是却是自己在2018年写的最后一篇博客了,昨天下班在地铁上闲来无事,翻起了关注的一些公众号发的技术博文,里面就提到写博客的重要性,其实这 ...

  9. Mybatis的核心配置

    之前了解了Mybatis的基本用法,现在学习一下Mybatis框架中的核心对象以及映射文件和配置文件,来深入的了解这个框架. 1.Mybatis的核心对象 使用MyBatis框架时,主要涉及两个核心对 ...

  10. 安装 jupyter notebook 出现 ModuleNotFoundError: No module named 'markupsafe._compat' 错误

    使用 python -m pip install jupyter 安装完成 jupyter notebook 之后,在命令行界面输入 "jupyter notebook "指令打开 ...