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< ...
随机推荐
- 使用 pjax 载入的新页面,新页面上 类方法 无法被触发?
在父页面上有定义类似 $(".class").click(function(){ ... }) 经过pjax 载入后的新页面 点击后没有触发事件 在segmentfault 上提问 ...
- windows下启动mysql服务的命令行启动和手动启动方法
1.图形界面下启动mysql服务. 在图形界面下启动mysql服务的步骤如下: (1)打开控制面板->管理工具->服务,如下图所示: 可以看到Mysql服务目前的状态是未启动(未写已启动的 ...
- 【leetcode 简单】第十五题 加一
给定一个非负整数组成的非空数组,在该数的基础上加一,返回一个新的数组. 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字. 你可以假设除了整数 0 之外,这个整数不会以零开头. 示例 1: ...
- 6.MySQL简介
MySQL简介 ·点击查看MySQL官方网站 ·MySQL是一个关系型数据库管理系统,由瑞典MySQLAB公司开发,后来被Sun公司收购,Sun公司后来又被Oracle公司收购,目前属于facle旗下 ...
- eclipse启动项目
今天做的任务不多,没有自己写代码,上午看了些文章,下午我司后台给配了配项目环境,全装C盘了..以后有我好受的.. 看着后台操作,修改了N多配置,tomcat.redis.zkServer..Nginx ...
- Android Service使用简单介绍
作为一个android初学者,经常对service的使用感到困惑.今天结合Google API 对Service这四大组件之一,进行简单使用说明. 希望对和我一样的初学者有帮助,如有不对的地方,也希望 ...
- Java从零到企业级电商项目实战
欢迎关注我的微信公众号:"Java面试通关手册"(坚持原创,分享各种Java学习资源,面试题,优质文章,以及企业级Java实战项目回复关键字免费领取)回复关键字:"电商项 ...
- 【Python学习】字符编码
先说两个基础知识. (1)计算机内部,数据是由0,1组成的: (2)计算机最小的数据单位,就是一个二进制单位即bit,接下来就是8个二进制单位表示一个字节(Byte). 1 ASCII码 ASCII码 ...
- anychat安装
1.下载后,解压到一个目录 2.进入anychat核心服务器目录,并启动 ①.cd %anychat安装路径%/binrver ②../anychatcoreserver -d 3.进 ...
- c json实战引擎六 , 感觉还行
前言 看到六, 自然有 一二三四五 ... 为什么还要写呢. 可能是它还需要活着 : ) 挣扎升级中 . c json 上面代码也存在于下面项目中(维护的最及时) structc json 这次版本 ...