SPOJ1557 GSS2
不知道第几次回顾了,每次回顾感觉都有新的收获
这题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的更多相关文章
- SPOJ1557 GSS2 Can you answer these queries II 历史最值线段树
传送门 题意:给出一个长度为$N$的数列,$Q$次询问,每一次询问$[l,r]$之间的最大子段和,相同的数只计算一次.所有数字的绝对值$\leq 10^5$ GSS系列中不板子的大火题,单独拿出来写 ...
- BZOJ2482: [Spoj1557] Can you answer these queries II
题解: 从没见过这么XXX的线段树啊... T_T 我们考虑离线做,按1-n一个一个插入,并且维护区间[ j,i](i为当前插入的数)j<i的最优值. 但这个最优值!!! 我们要保存历史的最优值 ...
- 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 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 ...
- 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 ...
- 【BZOJ2482】[Spoj1557] Can you answer these queries II 线段树
[BZOJ2482][Spoj1557] Can you answer these queries II Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和( ...
- SPOJ GSS2 Can you answer these queries II
Time Limit: 1000MS Memory Limit: 1572864KB 64bit IO Format: %lld & %llu Description Being a ...
- BZOJ2883 : gss2加强版
首先离散化颜色 设pre[x]表示与x颜色相同的点上一次出现的位置,对于每种颜色开一个set维护 修改时需要修改x.x修改前的后继.x修改后的后继 询问[l,r]等价于询问[l,r]内pre[x]&l ...
- 【SPOJ - GSS2】Can you answer these queries II(线段树)
区间连续不重复子段最大值,要维护历史的最大值和当前的最大值,打两个lazy,离线 #include<cstdio> #include<cstring> #include< ...
随机推荐
- fetch and js异步介绍
http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html Javascript异步编程的4种方法 ht ...
- Broken Necklace
Description 你有一条由N个红色的,白色的,或蓝色的珠子组成的项链(3<=N<=350),珠子是随意安排的. 这里是 n=29 的二个 例子: 1 2 1 2 r b b r b ...
- LintCode之二叉树的最大节点
分治问题,可以把整棵树看做是由一颗颗只有三个节点组成的小树,一颗树的构成是根节点.左子树.右子树,这样只需要从左子树找出一个最大的节点,从右子树找出一个最大的节点,然后与根节点三个取个最大的,就是最终 ...
- 使用Bash时的几点总结
作为一个天天与Linux打交道,并以此为生的Linux运维工程师,最常用的工具性语言恐怕就是shell了, 而对于大多数的Linux和一些类Unix而言,其默认的shell就是Bash.使用Bash一 ...
- Class类和ClassLoader类的简单介绍
反射机制中的Class Class内部到底有什么呢?看下图! 代码: Class cls=Person.class; 1.Class类: 1. 对象照镜子后可以得到的信息:某个类的数据成员名,方法和构 ...
- FusionCharts 用法心得
现在主流的很多jQuery+js结合的图表展示插件,有HighCharts,ECharts等等,今天我们先来了解一下FusionCharts,也是一个非常不错的图表制作工具.希望我的同事以及其他需要帮 ...
- 8.Python3标准库--数据持久存储与交换
''' 持久存储数据以便长期使用包括两个方面:在对象的内存中表示和存储格式之间来回转换数据,以及处理转换后数据的存储区. 标准库包含很多模块可以处理不同情况下的这两个方面 有两个模块可以将对象转换为一 ...
- 修改帧大小和socket缓冲区大小(转)
修改帧大小和socket缓冲区大小 MTU (最大传输单元)的缺省值为1500. 通过下面命令将其改为9000(jumbo frame) % ifconfig eth0 mtu 9000 socket ...
- C# 中DateTime的各种使用
获得当前系统时间: DateTime dt = DateTime.Now; Environment.TickCount可以得到“系统启动到现在”的毫秒值 DateTime now = DateTime ...
- 用 python 来操作 docx, xlsx 格式文件(二)(使用 docx 库操作 docx 格式文件
docx 库 文章结构: 一.docx 基本用,创建 docx 文件并添加数据 二.深入理解文本格式(format),并设置所格式属性(attribute) 三.深入理解样式(styles),以及如何 ...