传送门

题意:给出一个长度为$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. 使用Topshelf创建自宿主的Windows服务程序

    在传统的Windows服务开发过程中,需要添加一个服务安装程序,里面写安装,启动和停止服务等逻辑.现在,使用TopSelf可以简化这个过程.具体请看官网说明: http://docs.topshelf ...

  2. eclipse显示代码行数

    最近做的手机APP正在进行最后一部分了,在一个类中估计要写上千行代码,来回的拉动滚动条太麻烦了,于是发现为什么我得eclipse不显示代码行数呢  其他C什么的编译器都显示的. 于是百度了一下,一下子 ...

  3. [20180122]列统计与直方图.txt

    [20180122]列统计与直方图.txt --//昨天看了https://jonathanlewis.wordpress.com/2018/01/18/column-stats/,提到分析metho ...

  4. Asp.net Mvc身份验证

    1.安装组件 Microsoft.AspNet.Identity.Core,身份认证核心组件 安装Microsoft.AspNet.Identity.EntityFramework,EF实现身份认证 ...

  5. linux调度器源码分析 - 概述(一)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 引言 调度器作为操作系统的核心部件,具有非常重要的意义,其随着linux内核的更新也不断进行着更新.本系列文章通 ...

  6. Django学习---py3下的富文本编辑器的使用

    背景说明: Ueditor HTML编辑器是百度开源的HTML编辑器,但是在Python3下调用报错,找不到widgets模块,经查发现,DjangoUeditor是基于Python 2.7的,对Py ...

  7. sql server 2008R2无人值守批处理脚本自动化安装

    ▲版权声明:本文为博主原创文章,未经博主允许不得转载. Microsoft SQL Server 2008 R2是一款软件,提供完整的企业级技术与工具,帮助您以最低的总拥有成本获得最有价值的信息.您可 ...

  8. Flask消息闪现

    目录 Flask消息闪现 简单的例子 闪现消息的类别 过滤闪现消息 Message Flashing 参考 Flask消息闪现 一个好的应用和用户界面都需要良好的反馈.如果用户得不到足够的反馈,那么应 ...

  9. 【PAT】B1075 链表元素分类(25 分)

    这道题算有点难,心目中理想的难度. 不能前怕狼后怕虎,一会担心超时,一会又担心内存过大,直接撸 将三部分分别保存到vector 有意思的在于输出 分别输出第一个的add和num 中间输出nextadd ...

  10. February 9th, 2018 Week 6th Friday

    Every one of us want to ameliorate our own condition. You can only cure retail but you can prevent w ...