ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SP1557 GSS2 - Can you answer these queries II

2022-08-31 10:00:08  阅读:172  来源: 互联网

标签:pre these sum 离线 SP1557 II 区间 维护 我们


SP1557 GSS2 - Can you answer these queries II

题目大意

给出 \(n\) 个数,\(q\) 次询问,求最大子段和,相同的数只算一次。

分析

看到一个区间内相同的数只能算一次,经验告诉我们要考虑离线

我们将区间按照右端点排序,用pre[i]来表示i上次出现的位置。

接下来,我们来考虑线段树需要维护什么。

首先,我们考虑之前不加条件时,我们维护的值还可以维护嘛?

很显然,不太可行,因为当一个区间出现多个值的时候,我们不知道需要哪个位置的值,而其他的不要。

我们考虑从离线角度思考,我们维护四个值sum,stag,hismax,htag。假设此时是以y为结尾的区间。

  • sum[i]表示从[i,y]的所有值只算一次的和
  • stag表示区间加懒标记
  • hismax[i]表示以i为起点,终点小于t的所有区间的最大值
  • htag历史加懒标记,当多个区间加操作发生时,我们只加其中最大的。

那具体怎么加,才能使得所有值值算一次的和呢?

还记得,我们有一个pre[i]嘛,此时我们直接从[pre[i]+1,i]区间加上w[i]

这样我们能保证,相同的值,不会多次对sum造成影响。

这个思路非常巧妙,我们再来顺一遍。

我们,想要保证一个区间内相同的值只被算一次,同时加上离线。

我们考虑维护sum,同时每次碰到一个节点i,我们区间加[pre[i]+1,i],这样可以保证该值的影响只影响到前面从上一次遇到相同的值的位置的下一个到现在的所有位置。这个消除多个影响的设计在于,如果我们直接维护和,这样就可以通过限定区域来限定影响。同时这个和的设计也很巧妙。其利用了离线的状态去设计了和的状态定义。

具体的一些维护细节,可以直接看代码。

Ac_code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
struct Node
{
    int l,r;
    LL sum,stag,hismax,htag;
}tr[N<<2];
struct Line
{
    int l,r,id;
    bool operator<(const Line& W)const 
    {
        return r<W.r;
    }
}line[N];
int w[N],pos[2*N+10];
LL ans[N];
int n,m;

void push(Node &u,Node &l,Node &r)
{
    u.sum = max(l.sum,r.sum);
    u.hismax = max(l.hismax,r.hismax);
}

void pushup(int u)
{
    push(tr[u],tr[u<<1],tr[u<<1|1]);
}

void pushdown(int u)
{
    auto &root = tr[u],&left = tr[u<<1],&right = tr[u<<1|1];
    left.hismax = max(left.hismax,left.sum+root.htag);//每次只加加序列的最大值
    left.sum += root.stag;
    left.htag = max(left.htag,left.stag+root.htag);//维护累积加序列的最大值
    left.stag += root.stag;
    right.hismax = max(right.hismax,right.sum+root.htag);
    right.sum += root.stag;
    right.htag = max(right.htag,right.stag+root.htag);
    right.stag += root.stag;
    root.stag = root.htag = 0;
}

void build(int u,int l,int r)
{
    tr[u] = {l,r};
    if(l==r) return ;
    int mid = l + r >> 1;
    build(u<<1,l,mid),build(u<<1|1,mid+1,r);
}

void modify(int u,int l,int r,int k)
{
    if(l<=tr[u].l&&tr[u].r<=r)
    {
        tr[u].sum += k;
        tr[u].hismax = max(tr[u].hismax,tr[u].sum);
        tr[u].stag += k;
        tr[u].htag = max(tr[u].htag,tr[u].stag);
        return ;
    }
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if(l<=mid) modify(u<<1,l,r,k);
    if(r>mid) modify(u<<1|1,l,r,k);
    pushup(u);
}

Node query(int u,int l,int r)
{
    if(l<=tr[u].l&&tr[u].r<=r) return tr[u];
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if(r<=mid) return query(u<<1,l,r);
    else if(l>mid) return query(u<<1|1,l,r);
    else 
    {
        auto left = query(u<<1,l,r);
        auto right = query(u<<1|1,l,r);
        Node res;
        push(res,left,right);
        return res;
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",w+i);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int l,r;scanf("%d%d",&l,&r);
        line[i] = {l,r,i};
    }
    sort(line+1,line+1+m);
    build(1,1,n);
    int idx = 1;
    for(int i=1;i<=m;i++)
    {
        for(int j=idx;j<=line[i].r;j++)
        {
            modify(1,pos[w[j]+N]+1,j,w[j]);
            pos[w[j]+N] = j;
        }
        ans[line[i].id] = query(1,line[i].l,line[i].r).hismax;
        idx = line[i].r + 1;
    }
    for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
    return 0;
}

标签:pre,these,sum,离线,SP1557,II,区间,维护,我们
来源: https://www.cnblogs.com/aitejiu/p/16641967.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有