zoukankan      html  css  js  c++  java
  • 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 MB
    Submit: 145  Solved: 76
    [Submit][Status][Discuss]

    Description

    给定n个元素的序列。
    给出m个询问:求l[i]~r[i]的最大子段和(可选空子段)。
    这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次。
    比如:1,2,3,2,2,2出现了3次,但只算一次,于是这个序列的和是1+2+3=6。

    Input

     

    第一行一个数n。
    第二行n个数,为给定的序列,这些数的绝对值小于等于100000。
    第三行一个数m。
    接下来m行,每行两个数,l[i],r[i]。

    Output

    M行,每行一个数,为每个询问的答案。

    Sample Input

    9
    4 -2 -2 3 -1 -4 2 2 -6
    3
    1 2
    1 5
    4 9


    Sample Output


    4
    5
    3

    HINT

    【数据说明】

    30%:1 <= n, m <= 100

    100%:1 <= n, m <= 100000

      一年前抄标程把spoj的gss2做了,一年后重新做了一遍,仍然把我恶心的。。。。【话说这道题没卡longlong很不爽】

      还是一步一步想吧,首先是离线,转成线段树的区间加,询问区间最大值的历史最大值。

      这东西怎么搞呢?

      我们先不考虑下放标记的问题,单考虑一个结点。

      记录plus[]表示从上次清除tag到现在,已经有多少“加”操作下降到当前点。

      记录hplus[]表示从上次清除tag到现在,历史加操作“峰值”与plus的差值。

      在不考虑下放的情况下每次加v操作及plus+=v,hplus=max(0,hplus-v);

      当然作为线段树,我们还要记录maxv表示当前区间的答案,及区间历史最大值。

      然后再考虑标记下方问题。

      在调试中发现单纯maxv很难维护,需要在加一个中间变量,视为nmaxv,及当前最大值。

      转移什么的知道变量含义就可以参考代码了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<assert.h>
    using namespace std;
    #define MAXN 110000
    #define MAXQ MAXN
    #define MAXT MAXN*5
    #define lch (now<<1)
    #define rch (now<<1^1)
    #define smid ((l+r)>>1)
    #define INF 0x3f3f3f3f
    typedef long long qword;
    struct sgt_node
    {
            qword plus,maxv;
            qword hplus;
            qword nmaxv;
    }sgt[MAXT];
    void make_plus(int now,qword v)
    {
            sgt[now].hplus-=v;
            sgt[now].plus+=v;
            sgt[now].hplus=max(sgt[now].hplus,0ll);
            sgt[now].nmaxv+=v;
            sgt[now].maxv=max(sgt[now].maxv,sgt[now].nmaxv+sgt[now].hplus);
    }
    void down(int now)
    {
            make_plus(lch,sgt[now].plus+sgt[now].hplus);
            make_plus(lch,-sgt[now].hplus);
            make_plus(rch,sgt[now].plus+sgt[now].hplus);
            make_plus(rch,-sgt[now].hplus);
            sgt[now].plus=sgt[now].hplus=0;
            assert(sgt[now].maxv==max(sgt[lch].maxv,sgt[rch].maxv));
    }
    void Build_sgt(int now,int l,int r)
    {
            sgt[now].plus=0;
            sgt[now].hplus=0;
            sgt[now].maxv=0;
            if (l==r)return ;
            Build_sgt(lch,l,smid);
            Build_sgt(rch,smid+1,r);
    }
    void Add_sgt(int now,int l,int r,int x,int y,qword v)
    {
            if (l==x && r==y)
            {
                    make_plus(now,v);
                    return ;
            }
            down(now);
            if (y<=smid)
                    Add_sgt(lch,l,smid,x,y,v);
            else if (smid<x)
                    Add_sgt(rch,smid+1,r,x,y,v);
            else 
            {
                    Add_sgt(lch,l,smid,x,smid,v);
                    Add_sgt(rch,smid+1,r,smid+1,y,v);
            }
            sgt[now].nmaxv=max(sgt[lch].nmaxv,sgt[rch].nmaxv);
            sgt[now].maxv=max(sgt[lch].maxv,sgt[rch].maxv);
    }
    qword Query_sgt(int now,int l,int r,int pos)
    {
            if (l==r)
                    return sgt[now].maxv+sgt[now].plus+sgt[now].hplus;
            down(now);
            if (pos<=smid)
                    return Query_sgt(lch,l,smid,pos);
            else 
                    return Query_sgt(rch,smid+1,r,pos);
    }
    int Query_sgt(int now,int l,int r,int x,int y)
    {
            if (l==x && r==y)
                    return sgt[now].maxv;
            down(now);
            if (y<=smid)
                    return Query_sgt(lch,l,smid,x,y);
            else if (smid<x)
                    return Query_sgt(rch,smid+1,r,x,y);
            else
                    return max(Query_sgt(lch,l,smid,x,smid),Query_sgt(rch,smid+1,r,smid+1,y));
    }
    int a[MAXN],lastid[MAXN*2],prv[MAXN];
    struct qur_t
    {
            int l,r,id;
            qword ans;
    }qur[MAXQ];
    bool cmp_r(qur_t q1,qur_t q2)
    {
            return q1.r<q2.r;
    }
    bool cmp_id(qur_t q1,qur_t q2)
    {
            return q1.id<q2.id;
    }
    int main()
    {
            freopen("input.txt","r",stdin);
    //        freopen("output.txt","w",stdout);
            int n,m;
            scanf("%d",&n);
            for (int i=1;i<=n;i++)
            {
                    scanf("%d",a+i);
                    prv[i]=lastid[a[i]+MAXN];
                    lastid[a[i]+MAXN]=i;
            }
            scanf("%d",&m);
            for (int i=0;i<m;i++)
            {
                    scanf("%d%d",&qur[i].l,&qur[i].r);
                    qur[i].id=i;
            }
            sort(qur,qur+m,cmp_r);
            int qn=0;
            for (int i=1;i<=n;i++)
            {
                //    fprintf(stderr,"%d
    ",i);
                    Add_sgt(1,1,n,prv[i]+1,i,a[i]);
                    while (qn<m && qur[qn].r==i)
                    {
                            qur[qn].ans=Query_sgt(1,1,n,qur[qn].l,qur[qn].r);
                            qn++;
                    }
            }
            sort(qur,qur+m,cmp_id);
            for (int i=0;i<m;i++)
                    printf("%lld
    ",qur[i].ans);
    }
  • 相关阅读:
    PHP实现无限极分类
    html2canvas生成并下载图片
    一次线上问题引发的过程回顾和思考,以更换两台服务器结束
    Intellij IDEA启动项目报Command line is too long. Shorten command line for XXXApplication or also for
    mq 消费消息 与发送消息传参问题
    idea 创建不了 java 文件
    Java switch 中如何使用枚举?
    Collections排序
    在idea 设置 git 的用户名
    mongodb添加字段和创建自增主键
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4442736.html
Copyright © 2011-2022 走看看