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

这题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】2154: Crash的数字表格 莫比乌斯反演

    [题意]给定n,m,求Σlcm(i,j),1<=i<=n,1<=j<=m,n,m<=10^7. [算法]数论(莫比乌斯反演) [题解] $$ans=\sum_{i\leq ...

  2. 网易android开发面试题及心得

    前几天面试网易android开发,总体感觉问题难度一般.怪我自己没有好好梳理知识,尤其是基础,后面就没消息了... 笔试: 1.描述Activity 生命周期 2.什么是ANR,如何规避? 3.描述a ...

  3. 深入理解Spring系列之十一:SpringMVC-@RequestBody接收json数据报415

    转载 https://mp.weixin.qq.com/s/beRttZyxM3IBJJSXsLzh5g 问题原因 报错原因可能有两种情况: 请求头中没有设置Content-Type参数,或Conte ...

  4. (5)剑指Offer之栈变队列和栈的压入、弹出序列

    一 用两个栈实现队列 题目描述: 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 问题分析: 先来回顾一下栈和队列的基本特点: 栈:后进先出(LIFO) 队列: ...

  5. java反序列化漏洞

    http://www.freebuf.com/vuls/86566.html 有时间了  仔细阅读

  6. ubuntu之安装pycharm编辑器

    pycharm是Java写的,运行需要Java环境. 安装java jdk sudo add-apt-repository ppa:webupd8team/java sudo apt-get upda ...

  7. 2017-2018 ACM-ICPC, NEERC, Southern Subregional Contest, qualification stage

    2017-2018 ACM-ICPC, NEERC, Southern Subregional Contest, qualification stage A. Union of Doubly Link ...

  8. 解决su – 后显示-bash-4.1#

    <1>现象 设置tfs的管理用户时. su - admin时,出现 -bash-4.1# <2>解决 chown  admin:admin /home/admin        ...

  9. java版云笔记(三)

    登录与注册写好了下来就是主页,今天写的是主页加载时笔记本列表的显示,ajax是固定的就不重点说了.主要说一下jQuery.data() 函数和jQuery.on() 函数. 注:这个项目的sql文件, ...

  10. django时差8个小时问题

    问题现象: 在用django做好的网站,上传图片后显示的发布时间比当前时间差了8小时 查找问题: 查看服务器系统时间,经查与当前时间一致,无问题 查看数据库中的时间也一样 最终原因: 在setting ...