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

这题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. Eng1—English daily notes

    English daily notes 2015年 4月 Phrases As a side note 作为附注,顺便说句题外话,和by the way意思相近,例句 As a side note, ...

  2. 【BZOJ】1492: [NOI2007]货币兑换Cash

    [题意]初始资金s,有两种金券A和B,第i天,买入时将投入的资金购买比例为rate[i]的两种股票,卖出时将持有的一定比例的两种股票卖出,第i天股票价格为A[i],B[i],求最大获利.n<=1 ...

  3. 2017ACM暑期多校联合训练 - Team 2 1011 HDU 6055 Regular polygon (数学规律)

    题目链接 **Problem Description On a two-dimensional plane, give you n integer points. Your task is to fi ...

  4. Django之组合搜索组件(一)

    什么是组合搜索呢? 比如你想买车,但手里只有10万块!所以你只能在10万块的车里挑选,但你喜欢黑色,因为觉得很高端大气上档次,说白了就是装逼杠杠的!之后售车姐给你拿了个表表,你看到了低于10万块且颜色 ...

  5. [002] delete_duplication_of_linked_list

    [Description] Given a unsort linked list, delete all the duplication from them, no temporary space p ...

  6. git-定制属于你的log格式

    软件版本:    操作系统:ubuntu10.04     内核版本:Linux version 2.6.32-36-generic     git 版本:git version 1.7.0.4 1. ...

  7. HDU 6197 array array array 2017沈阳网络赛 LIS

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6197 题意:给你n个数,问让你从中删掉k个数后(k<=n),是否能使剩下的序列为非递减或者非递增 ...

  8. css3动画详解

    一.Keyframes介绍: Keyframes被称为关键帧,其类似于Flash中的关键帧.在CSS3中其主要以“@keyframes”开头,后面紧跟着是动画名称加上一对花括号“{…}”,括号中就是一 ...

  9. 使用Jackson来实现Java对象与JSON的相互转换的教程

    一.入门Jackson中有个ObjectMapper类很是实用,用于Java对象与JSON的互换.1.JAVA对象转JSON[JSON序列化] 1 2 3 4 5 6 7 8 9 10 11 12 1 ...

  10. python函数库及函数标准库

    一.系统库提供的内部函数 字符函数库: 1)str.islower() :字符串是否全部是小写 2)str.isspace() :字符串是否为空 3)help(str):查询字符串函数库 4)str. ...