传送门

题意:给出一个长度为$N$的数列,$Q$次询问,每一次询问$[l,r]$之间的最大子段和,相同的数只计算一次。所有数字的绝对值$\leq 10^5$


GSS系列中不板子的大火题,单独拿出来写

因为相同的数字只计算一次,像GSS1中的合并操作就无法进行,传统做法失效,我们需要一种更强大的做法。

考虑到去重,与HH的项链很相似,所以考虑离线、对询问以$r$从小到大进行排序后进行计算。

考虑到每一次$r$的增加都会产生新的可能的最大子段和,我们用如下方式维护线段树:对于第$i$个叶子节点,它包含两个元素:$sum$表示$\sum \limits_i^r num_i$(不算重复元素),$hisMax$表示$\sum \limits_i^r num_i$在曾经的过程中取到的最大值(也就是左端点为$l$,右端点在$[l,r]$之间的最大子段和)。而对于每一个非叶子节点,它的$sum$和$hisMax$都取其左右儿子的最大值。这样每一次询问操作只需要询问$[l,r]$的$hisMax$即可。

对于$r$的右移操作,设$pre_i$表示数字$i$最后一次出现的位置,将右端点从$r$移到$r+1$的过程就是对$pre_{num_{r+1}}$到$r+1$的所有位置加上$num_{r+1}$的操作。

考虑到复杂度,所以我们需要用到懒标记,而pushdown在其中是十分讲究的,具体代码和解释在下面

($h\_tag$表示$hisMax$的标记(相当于在当前$hisMax$还需要加多少),$s\_tag$表示$sum$的懒标记)

inline void pushdown(int now){
    if(Tree[now].h_tag){
        Tree[lch].hisMax = max(Tree[lch].hisMax , Tree[lch].sum + Tree[now].h_tag);
        Tree[rch].hisMax = max(Tree[rch].hisMax , Tree[rch].sum + Tree[now].h_tag);
        Tree[lch].h_tag = max(Tree[lch].h_tag , Tree[lch].s_tag + Tree[now].h_tag);
        Tree[rch].h_tag = max(Tree[rch].h_tag , Tree[rch].s_tag + Tree[now].h_tag);
/*
h_tag和hisMax实质上都是前缀最大值
在一个后缀加入的时候(也就是Tree[now].h_tag传下来的时候),s_tag和sum可以跟当前的h_tag接上变成一个新的前缀而s_tag与h_tag两个标记对应的区间的左端点一定是一致的,sum和hisMax显然是一致的,于是h_tag和hisMax可以这样转移
*/
        Tree[now].h_tag = ;
    }
    if(Tree[now].s_tag){
        Tree[lch].sum += Tree[now].s_tag;
        Tree[rch].sum += Tree[now].s_tag;
        Tree[lch].s_tag += Tree[now].s_tag;
        Tree[rch].s_tag += Tree[now].s_tag;
        Tree[now].s_tag = ;
    }//这个没什么好说的,基本的线段树操作
}
//注意一定要先传h_tag再传s_tag,因为h_tag和hisMax传下来的时候是与之前的那一段进行连接,而不是与当前计算的这一段进行连接

完整代码:

 #include<bits/stdc++.h>
 #define lch (now << 1)
 #define rch (now << 1 | 1)
 #define mid ((l + r) >> 1)
 #define int long long
 //This code is written by Itst
 using namespace std;

 inline int read(){
     ;
     ;
     char c = getchar();
     while(c != EOF && !isdigit(c)){
         if(c == '-')
             f = ;
         c = getchar();
     }
     while(c != EOF && isdigit(c)){
         a = (a << ) + (a << ) + (c ^ ');
         c = getchar();
     }
     return f ? -a : a;
 }

 ;
 struct node{
     int sum , hisMax , s_tag , h_tag;
 }Tree[MAXN << ];
 struct query{
     int l , r , ind;
 }now[MAXN];
 map < int , int > appear;
 int N , Q , num[MAXN] , ans[MAXN];

 bool operator <(query a , query b){
     return a.r < b.r;
 }

 inline void pushup(int now){
     Tree[now].sum = max(Tree[lch].sum , Tree[rch].sum);
     Tree[now].hisMax = max(Tree[lch].hisMax , Tree[rch].hisMax);
 }

 inline void pushdown(int now){
     if(Tree[now].h_tag){
         Tree[lch].hisMax = max(Tree[lch].hisMax , Tree[lch].sum + Tree[now].h_tag);
         Tree[rch].hisMax = max(Tree[rch].hisMax , Tree[rch].sum + Tree[now].h_tag);
         Tree[lch].h_tag = max(Tree[lch].h_tag , Tree[lch].s_tag + Tree[now].h_tag);
         Tree[rch].h_tag = max(Tree[rch].h_tag , Tree[rch].s_tag + Tree[now].h_tag);
         Tree[now].h_tag = ;
     }
     if(Tree[now].s_tag){
         Tree[lch].sum += Tree[now].s_tag;
         Tree[rch].sum += Tree[now].s_tag;
         Tree[lch].s_tag += Tree[now].s_tag;
         Tree[rch].s_tag += Tree[now].s_tag;
         Tree[now].s_tag = ;
     }
 }

 void modify(int now , int l , int r , int L , int R , int add){
     if(l >= L && r <= R){
         Tree[now].s_tag += add;
         Tree[now].sum += add;
         Tree[now].hisMax = max(Tree[now].hisMax , Tree[now].sum);
         Tree[now].h_tag = max(Tree[now].h_tag , Tree[now].s_tag);
         return;
     }
     pushdown(now);
     if(mid >= L)
         modify(lch , l , mid , L , R , add);
     if(mid < R)
         modify(rch , mid +  , r , L , R , add);
     pushup(now);
 }

 int query(int now , int l , int r , int L , int R){
     if(l >= L && r <= R)
         return Tree[now].hisMax;
     pushdown(now);
     ;
     if(mid >= L)
         maxN = query(lch , l , mid , L , R);
     if(mid < R)
         maxN = max(maxN , query(rch , mid +  , r , L , R));
     return maxN;
 }

 signed main(){
 #ifndef ONLINE_JUDGE
     freopen("1557.in" , "r" , stdin);
     //freopen("1557.out" , "w" , stdout);
 #endif
     N = read();
      ; i <= N ; ++i)
         num[i] = read();
     Q = read();
      ; i <= Q ; ++i){
         now[i].l = read();
         now[i].r = read();
         now[i].ind = i;
     }
     sort(now +  , now + Q + );
      ; i <= Q ; ++i){
         ].r +  ; j <= now[i].r ; ++j){
             modify( ,  , N , appear[num[j]] +  , j , num[j]);
             appear[num[j]] = j;
         }
         ans[now[i].ind] = query( ,  , N , now[i].l , now[i].r);
     }
      ; i <= Q ; ++i)
         printf("%lld\n" , ans[i]);
     ;
 }

SPOJ1557 GSS2 Can you answer these queries II 历史最值线段树的更多相关文章

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

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

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

  4. SPOJ GSS2 Can you answer these queries II

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

  5. SP1557 GSS2 - Can you answer these queries II

    一开始看不懂题解,看懂了题解之后觉得还是挺妙的. 好多题解里都提到了HH的项链,但是我觉得关系并不大啊…… 先把所有询问离线下来按照右端点排序,按照询问的要求一个一个加入数字,怎么加入数字,我们设计一 ...

  6. SPOJ GSS2 Can you answer these queries II ——线段树

    [题目分析] 线段树,好强! 首先从左往右依次扫描,线段树维护一下f[].f[i]表示从i到当前位置的和的值. 然后询问按照右端点排序,扫到一个位置,就相当于查询区间历史最值. 关于历史最值问题: 标 ...

  7. SP1557 GSS2 - Can you answer these queries II(线段树)

    传送门 线段树好题 因为题目中相同的只算一次,我们可以联想到HH的项链,于是考虑离线的做法 先把所有的询问按$r$排序,然后每一次不断将$a[r]$加入线段树 线段树上维护四个值,$sum,hix,s ...

  8. SPOJ 1557 GSS2 - Can you answer these queries II (线段树+维护历史最值)

    都说这题是 GSS 系列中最难的,今天做了一下,名副其实 首先你可以想到各种各样的在线乱搞想法,线段树,主席树,平衡树,等等,但发现都不太可行. 注意到题目也没有说强制在线,因此可以想到离线地去解决这 ...

  9. Can you answer these queries I SPOJ - GSS1 (线段树维护区间连续最大值/最大连续子段和)

    You are given a sequence A[1], A[2], ..., A[N] . ( |A[i]| ≤ 15007 , 1 ≤ N ≤ 50000 ). A query is defi ...

随机推荐

  1. SD从零开始64-特异的业务交易(Special Business Transactions)

    紧迫订单Rush Orders 紧迫订单和现金销售是用在从工厂销售流程可能用于当客户需要求即刻从货场获得他们的货物时的销售凭据种类: 在即刻交货的销售凭据种类中,即刻交货符号和交货种类DF是设置的:当 ...

  2. 使用Twitter异常检测框架遇到的坑

    在Github上搜索“Anomaly Detection”,Twitter的异常检测框架(基于R语言)高居榜首,可见效果应该不错: 但是活跃度并不高,3-4年没人维护了: 因此在使用时难免会遇到一些坑 ...

  3. lombok的简单介绍(1)

    一.项目背景 在写Java程序的时候经常会遇到如下情形: 新建了一个Class类,然后在其中设置了几个字段,最后还需要花费很多时间来建立getter和setter方法 lombok项目的产生就是为了省 ...

  4. CRM原型

    https://files.cnblogs.com/files/wcLT/CRM.zip

  5. 辽宁移动宽带体验及魔百盒M101s-2刷机

    一.背景 坐标:辽宁 某城,移动宽带100M. 设备:移动赠送,华为光猫一只,魔百盒M101s-2电视盒子 一只,据安装人员说这个魔百盒是移动自己开发设计的. 二.上网体验 上网:浏览一般网站没问题. ...

  6. 离群点检测与序列数据异常检测以及异常检测大杀器-iForest

    1. 异常检测简介 异常检测,它的任务是发现与大部分其他对象不同的对象,我们称为异常对象.异常检测算法已经广泛应用于电信.互联网和信用卡的诈骗检测.贷款审批.电子商务.网络入侵和天气预报等领域.这些异 ...

  7. 什么是ORM?为啥要是用ORM?

    了解orm,先了解以下概念: 什么是“持久化” 持久(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘).持久化的主要应用是将内存中的数据存储在关系型的数据库中 ...

  8. python——虚拟环境之virtualenv(windows10,64位)

    1 问题 当我们拥有两个甚至多个项目A.B.C......,各个项目正常运行需求的python运行环境都不相同.而默认情况下,不管哪个项目,使用的都是全局的Python环境.上述情况,造成的问题就是, ...

  9. emacs org-mode文件转html文件

    Table of Contents 1. 发布站点 by emacs org-mode 1.1 org-mode 自带的导出方法 1.2 批量导出 1.3 css 美化 1.4 导出html 1. 发 ...

  10. java死锁详解

    进程死锁及解决办法: 一:死锁的概念:    死锁是进程死锁的简称    什么是死锁:    死锁是指多个进程循环等待他方占有的资源而无限的僵持下去的局面.很显然,没有外力作用,那么死锁涉及到的各个进 ...